/* Bible Biker Ministries — GO HARD mockup: content pages.
 *
 * Components shared by the sermons index, the 16 sermon pages and the
 * Bible-studies (podcast) page: the page hero, the art-card grid, the
 * reading column, the episode grid. One sheet rather than a <style> block
 * per page because the sermon pages are generated from one template
 * (tools/build-sermons.py) and a rule that lives in 18 identical copies is
 * exactly the drift DESIGN.md exists to prevent. Every value here is a
 * token from tokens.css; layout-only values (grid columns, a rotation) are
 * the known-gap exception DESIGN.md already allows.
 */

/* ---- Page hero: leather, like the homepage hero, but the copy is the
   page's own title, no wordmark banner. The art (when a page has one)
   sits to the right as a rotated print with a lifted shadow. ---- */
.page-hero {
  background-image: var(--surface-leather-dark); background-size: cover;
  color: var(--cream); position: relative; overflow: hidden;
}
.page-hero-inner {
  max-width: var(--measure-wide); margin: 0 auto;
  padding: clamp(2rem, 5vw, 3.5rem) var(--page-margin) clamp(2rem, 5vw, 3.5rem);
  display: grid; grid-template-columns: 1fr; gap: var(--gap-grid); align-items: center;
}
.page-hero-eyebrow {
  display: block; margin-bottom: .75rem; color: var(--gold);
  letter-spacing: var(--track-eyebrow); font-size: var(--text-micro);
  font-family: "Archivo Black"; text-transform: uppercase;
}
.page-hero-eyebrow a { color: inherit; text-decoration: none; }
.page-hero-eyebrow a:hover { text-decoration: underline; }
.page-hero h1 {
  font-family: "Anton", sans-serif; font-weight: 400; text-transform: uppercase;
  font-size: var(--text-title); line-height: var(--lh-tight); letter-spacing: -.005em;
  margin: 0 0 .75rem; color: var(--cream);
}
.page-hero h1 .accent { color: var(--gold); }
.page-hero .sub { color: var(--cream-soft); font-size: var(--text-lead); max-width: var(--measure-lead); margin: 0 0 .5rem; }
.page-hero .meta { color: var(--cream-soft); font-size: var(--text-label); margin: 0; }
.page-hero .meta em { color: var(--gold); font-style: normal; }
.page-hero .sub a { color: var(--gold); }
.page-hero-art { margin: 0; }
.page-hero-art img {
  width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: cover;
  transform: rotate(-1.4deg);
  box-shadow: var(--shadow-lift);
  filter: var(--grade-photo);
}
@media (min-width: 800px) {
  .page-hero-inner { grid-template-columns: minmax(0, 1fr) minmax(0, var(--hero-art-max)); gap: var(--hero-gap); }
  .page-hero-inner > div:first-child { max-width: var(--hero-text-max); }
  .page-hero-art { max-width: var(--hero-art-max); justify-self: end; }
}

/* ---- Card grid: the illustrations are the page. Each card is a paper
   patch (--surface-patch-paper + --shadow-card, the round-4/5 recipe) with
   the art bleeding to the card's edge and the title in Anton below. ---- */
.groups { padding: 3rem var(--page-margin) 4rem; max-width: var(--measure-wide); margin: 0 auto; }
.group { margin: 0 0 var(--space-section); }
.group h2.slab { margin-bottom: .35rem; }
/* round 39 (Mike): no row of category icons at the top of the store; each icon
   sits at the start of its own section heading instead. */
h2.slab:has(.sec-icon) { display: flex; align-items: flex-start; gap: .3em; }
h2.slab .sec-icon { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 1.15em; height: 1.15em; margin-top: calc((1em * var(--lh-caps) - 1.15em) / 2); border-radius: 50%; background: var(--black); box-shadow: var(--shadow-card); } /* round 40: centred on the first line of the heading, not the baseline */
h2.slab .sec-icon svg { width: 60%; height: 60%; fill: none; stroke: var(--gold); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.group-blurb { color: var(--ink-soft); font-size: var(--text-lead); max-width: var(--measure-lead); margin: 0 0 1.5rem; }
.card-grid {
  display: grid; grid-template-columns: 1fr; gap: var(--gap-card-sm);
}
@media (min-width: 600px) { .card-grid { grid-template-columns: repeat(2, 1fr); } } /* round 21: was 480; two-up cards were tight on phones with the bigger type (Mike) */
/* auto-fit, not a fixed count: a group of three fills three wide columns, a
   group of four fills four, no orphan cells. Checked against the real groups
   (3 / 4 / 3 / 6) at 700, 1100 and 1440px. */
@media (min-width: 700px)  { .card-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--gap-card); } } /* 280: four cards + three gaps fit the 1256px container at 1440 (Fable measured 300 leaving 3+1 orphans). auto-fill, not auto-fit, so a lone card (Store's digital download) stays card-sized instead of filling the row. */
@media (min-width: 1000px) { .card-grid.sermon-cards, .card-grid.lessons { grid-template-columns: repeat(3, 1fr); } }
/* Listen / Read tags and the subject jump list on the combined Bible Studies page (round 16). */
/* Round 21 (Mike): the Listen/Read words became icons (headphones, open
   book) on a small colored chip; the meta after them ("Lesson 13 · 27:54",
   "The Sabbath · 13 min") runs in Literata small caps instead of the
   Archivo label face so the two stop competing. */
.tag { display: inline-flex; align-items: center; justify-content: center; width: 1.9em; height: 1.9em; margin-right: .5em; border-radius: 3px; color: var(--cream); vertical-align: middle; flex-shrink: 0; }
.tag svg { width: 1.15em; height: 1.15em; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.tag-listen { background: var(--blood); } .tag-read { background: var(--black); } /* not .read: that is the sermon reader container (Fable, review 9) */
.card-kicker .meta { font-family: "Literata", serif; font-variant-caps: all-small-caps; letter-spacing: .04em; font-size: calc(var(--text-micro) * 1.15); color: var(--ink-soft); text-transform: none; }
.jump { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin: 0 0 3rem; }
.jump-label { font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-wide); font-size: var(--text-micro); color: var(--ink-soft); margin-right: .5rem; }
.jump a { display: inline-block; padding: .45em .9em; border: 1px solid var(--gold-line); color: var(--ink); text-decoration: none; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-label); font-size: var(--text-micro); background: var(--paper); }
.jump a:hover { background: var(--gold); border-color: var(--gold); color: var(--black); }
.panel + .panel { margin-top: var(--space-panel); } /* round 16: more air between the story panels (Mike: "need more space after the teach it yourself card") */ /* review 5: the sermon groups are 3/4/3/6, which fill three columns and orphan in four */
/* A group of five or more gets a lead card, double-width, so one
   illustration is seen large before the rest sit as a shelf (set by the
   build script: 6 cards = lead 2x2 + 4 in a 4-column grid, no holes). */
@media (min-width: 700px) {
  /* .card-grid.lead 2x2 feature removed (review 5): at four columns it orphaned the Trinity group's sixth card and featured a two-minute paper. */
}
.card {
  display: flex; flex-direction: column; position: relative;
  background-image: var(--surface-patch-paper); background-size: cover;
  box-shadow: var(--shadow-card);
  color: var(--ink); text-decoration: none;
  transition: transform .18s ease, box-shadow .18s ease;
}
/* No dashed inset on cards: the stitched frame belongs to paper panels; on a
   card it ran across the illustration and read as noise (mobile check). */
.card:hover, .card:focus-visible { transform: translateY(var(--lift)); }
.card img {
  width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: cover;
  filter: var(--grade-card);
}
.card-text { display: flex; flex-direction: column; flex: 1; gap: .35rem; padding: 1rem 1.1rem 1.15rem; position: relative; z-index: 1; }
.card-kicker {
  color: var(--blood); letter-spacing: var(--track-eyebrow); font-size: var(--text-micro); line-height: var(--lh-label);
  font-family: "Archivo Black"; text-transform: uppercase; display: flex; align-items: center; flex-wrap: wrap; gap: .1em 0;
}
.card-title {
  margin: 0;
  font-family: "Anton", sans-serif; text-transform: none; letter-spacing: var(--track-tight); /* round 16: sentence case on cards sitewide; the case comes from the copy */
  font-size: var(--text-h3); line-height: var(--lh-snug); color: var(--ink);
  text-wrap: balance;
}
.card-deck { margin: 0; color: var(--ink-soft); font-size: var(--text-label); line-height: var(--lh-body); }
.card-meta { color: var(--ink-soft); font-size: var(--text-micro); margin-top: auto; padding-top: .35rem; }
@media (max-width: 699px) { .card-grid.sermon-cards .card-deck { display: none; } } /* two-up sermon cards on a phone: title + art carry it; every other grid (home doors, store products) keeps its deck (Fable, review 5) */
@media (min-width: 700px) {
}

/* ---- Reading a sermon: the paper panel, one column, book measure. ---- */
.read-band { padding: 3rem var(--page-margin) 4rem; background: var(--paper); }
.read {
  max-width: calc(var(--measure-read) + 2 * clamp(1.5rem, 6vw, 5rem));
  margin: 0 auto; position: relative;
  background-image: var(--surface-patch-paper); background-size: cover;
  box-shadow: var(--shadow-card);
  padding: var(--pad-panel-y) var(--pad-panel-x);
}
.read::before { content: ""; position: absolute; inset: 12px; border: 2px dashed var(--thread-line); pointer-events: none; }
.read > * { position: relative; }
.read-body { font-size: var(--text-body); line-height: var(--lh-body); }
.read-body h2 {
  font-family: "Anton", sans-serif; font-weight: 400; text-transform: uppercase;
  font-size: var(--text-callback); line-height: var(--lh-snug); letter-spacing: var(--track-tight);
  margin: 2.25rem 0 .75rem; padding-top: .7rem; border-top: 4px double var(--gold); color: var(--ink);
}
.read-body h3 {
  font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-label);
  font-size: var(--text-label); color: var(--blood); margin: 1.75rem 0 .5rem;
}
.read-body p { margin: 0 0 1.1em; }
.read-body .lead { font-size: var(--text-lead); font-weight: 500; }
.read-body sup { font-size: var(--sup-size); line-height: 0; color: var(--ink-soft); margin-right: .12em; }
.read-body blockquote {
  margin: 1.25em 0; padding: .4em 0 .4em 1.2em;
  border-left: 4px solid var(--blood); color: var(--ink);
}
.read-body blockquote p { margin: 0 0 .5em; }
.read-body blockquote p:last-of-type { margin-bottom: 0; }
.read-body blockquote.scripture { border-left-color: var(--gold); font-style: italic; }
.read-body blockquote.scripture sup { font-style: normal; }
.read-body cite {
  display: block; margin-top: .4em; font-style: normal;
  font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker);
  font-size: var(--text-micro); color: var(--blood);
}
.read-body blockquote.scripture cite { color: var(--thread); }
.read-body .ref { font-size: var(--text-label); color: var(--ink-soft); }
.read-body .remark { color: var(--ink-soft); font-style: italic; padding-left: 1.2em; border-left: 2px dotted var(--thread-line); }
.read-body .note { font-size: var(--text-label); color: var(--ink-soft); }
.read-body .closing {
  font-family: "Anton", sans-serif; text-transform: uppercase; letter-spacing: var(--track-tight);
  font-size: var(--text-callback); line-height: var(--lh-display); color: var(--blood);
  margin: 1.5em 0;
}
.read-body .signoff { font-style: italic; margin-top: 1.5em; }
.read-body ul.quotes { list-style: none; padding: 0; margin: 0 0 1.25em; }
.read-body ul.quotes li { margin: 0 0 .9em; padding: .4em 0 .4em 1.2em; border-left: 4px solid var(--blood); }
.read-body ul.attributes, .read-body ol.propositions { padding-left: 1.4em; }
.read-body ul.attributes li, .read-body ol.propositions li { margin: 0 0 .6em; }
.read-body ol.propositions li { font-size: var(--text-lead); }
.read-body ol.propositions .refs { font-size: var(--text-label); color: var(--ink-soft); }
.read-body ol.outline { padding-left: 1.6em; }
.read-body ol.outline > li { margin: 0 0 .8em; }
.read-body ol.outline-alpha { list-style: upper-alpha; padding-left: 1.6em; margin: .5em 0; }
.read-body ol.outline-alpha > li { margin: 0 0 .45em; }
.read-body ol.endnotes {
  margin-top: 2.5em; padding: 1em 0 0 1.4em; border-top: 1px solid var(--thread-line);
  font-size: var(--text-label); color: var(--ink-soft);
}
.read-body ol.endnotes li { margin: 0 0 .4em; }
.read-body a:not(.btn) { color: var(--blood); }

/* Below the paper: download, prev/next, back. */
.read-foot { max-width: calc(var(--measure-read) + 2 * clamp(1.5rem, 6vw, 5rem)); margin: 2rem auto 0; text-align: center; }
.read-foot .btn { margin-bottom: 1.75rem; }
.read-nav { display: grid; grid-template-columns: 1fr; gap: .75rem; margin-bottom: 1.25rem; text-align: left; }
@media (min-width: 560px) { .read-nav { grid-template-columns: 1fr 1fr; } }
.read-nav a {
  display: flex; align-items: center; gap: .85rem;
  background-image: var(--surface-patch-paper); background-size: cover; box-shadow: var(--shadow-card);
  padding: .65rem .8rem; text-decoration: none; color: var(--ink);
  font-family: "Anton", sans-serif; text-transform: uppercase; letter-spacing: var(--track-tight);
  font-size: var(--text-label); line-height: var(--lh-snug);
}
.read-nav a:hover { color: var(--blood); }
.read-nav img { width: var(--thumb); height: var(--thumb); object-fit: cover; flex-shrink: 0; }
.read-nav a.next { flex-direction: row-reverse; text-align: right; }
.read-nav small { display: block; font-family: "Archivo Black"; font-size: var(--text-micro); letter-spacing: var(--track-wide); color: var(--thread); }
.read-back { font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); font-size: var(--text-label); }
.read-back a { color: var(--blood); text-decoration: none; }
.read-back a:hover { text-decoration: underline; }

/* ---- Episodes (Bible studies): same card, plus a player. The number is the
   kicker; the art is the whole top of the card. ---- */
.episodes { display: grid; grid-template-columns: 1fr; gap: var(--gap-card-sm); }
@media (min-width: 560px)  { .episodes { grid-template-columns: repeat(2, 1fr); gap: var(--gap-card); } }
@media (min-width: 1000px) { .episodes { grid-template-columns: repeat(3, 1fr); } }
.episode { display: flex; flex-direction: column; }
.episode .card-text { padding-bottom: 1rem; }
.episode audio { width: 100%; margin-top: .6rem; }
.episode .card-meta { margin-top: .1rem; }
/* Round 16: the bonus episode (Tom's testimony) is a wide card at the top of
   the Bible Studies page: landscape photo, text, then the player under the
   whole card like every other card (Mike). */
.episode.featured { grid-column: 1 / -1; }
.episode.featured img { aspect-ratio: 21 / 9; max-height: var(--featured-max-h); object-fit: cover; object-position: center 35%; height: auto; }
.episode.featured > audio { width: calc(100% - 2 * var(--pad-card)); margin: 0 var(--pad-card) var(--pad-card); }
@media (min-width: 700px) { .episode.featured .card-text { padding-right: 25%; } }

/* Round 16: a full-bleed scene-setting photo (Mike: "use it somewhere big as context"). */
.atmos { background: var(--black); }
.atmos img { display: block; width: 100%; height: auto; max-height: 62vh; object-fit: cover; object-position: center 55%; filter: var(--grade-photo); }

/* Store: shop-by-category tiles under the hero (round 15). */
.cat-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gap-tight); }
@media (min-width: 700px) { .cat-grid { grid-template-columns: repeat(5, 1fr); } }
.cat { position: relative; display: block; aspect-ratio: 1 / 1; overflow: hidden; box-shadow: var(--shadow-card); text-decoration: none; }
.cat img { width: 100%; height: 100%; object-fit: cover; filter: var(--grade-photo); transition: transform .3s ease; }
.cat-icon { display: none; } /* round 37: icons replace the photos in the phone strip */
.cat:hover img { transform: scale(1.04); }
.cat span { position: absolute; left: 0; right: 0; bottom: 0; padding: .6rem .75rem; background: linear-gradient(to top, var(--black-veil), transparent); color: var(--cream); font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); font-size: var(--text-label); }

/* Paper panels used for the studies intro/story/curriculum. */
.panel {
  position: relative; max-width: var(--measure-panel); margin: 0 auto 2rem;
  background-image: var(--surface-patch-paper); background-size: cover;
  box-shadow: var(--shadow-card);
  padding: 2.5rem clamp(1.5rem, 6vw, 4rem);
}
.panel::before { content: ""; position: absolute; inset: 12px; border: 2px dashed var(--thread-line); pointer-events: none; }
.panel > * { position: relative; }
.panel p { color: var(--ink-soft); font-size: var(--text-lead); }
.panel blockquote { margin: 1.25em 0; padding: .4em 0 .4em 1.2em; border-left: 4px solid var(--gold); font-style: italic; color: var(--ink); }
.panel-grid { display: grid; grid-template-columns: 1fr; gap: var(--gap-panel); }
@media (min-width: 800px) { .panel-grid { grid-template-columns: 1fr 1fr; align-items: center; gap: var(--gap-wide); } }
.panel-grid img { filter: var(--grade-photo); transform: rotate(-1.4deg); box-shadow: var(--shadow-lift); }

footer.site-foot .build { opacity: .3; margin-left: .5em; font-size: .8em; } /* build stamp: Mike checks deploys by it on his phone; kept, quiet */
footer.site-foot { text-align: center; padding: 1.5rem var(--page-margin); font-size: var(--text-fine); color: var(--cream-faint); }
/* r105 (a11y audit): footer links rendered UA-default blue (#0000EE) on a
   near-black ground, 2.16:1 -- fails WCAG AA. Gold measures 9.68:1 on black
   (see tokens.css). Underlined so the link isn't color-only, and padded to
   a real ~24px touch target since the surrounding text is small. */
footer.site-foot a { color: var(--gold); text-decoration: underline; display: inline-block; min-height: 24px; line-height: 24px; padding: 0 .15rem; }
footer.site-foot a:hover, footer.site-foot a:focus-visible { color: var(--cream); }
footer.site-foot a:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }

/* ---- Video: plays in the page, never hands the visitor to youtube.com
   (standing rule). 16:9 by default, .portrait for Tom's vertical
   testimony video. ---- */
.video-embed { position: relative; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; background: var(--black); box-shadow: var(--shadow-card); }
.video-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.video-embed.portrait { aspect-ratio: 9 / 16; max-width: 380px; margin: 0 auto; }
.video-caption { text-align: center; font-size: var(--text-label); color: var(--ink-soft); margin: .5rem 0 0; text-wrap: balance; }
.video-row { display: grid; grid-template-columns: 1fr; gap: var(--gap-card-row); }
@media (min-width: 640px) { .video-row-2, .video-row-3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .video-row-3 { grid-template-columns: repeat(3, 1fr); } }

/* round 82: video facade -- a poster image + play button standing in for the
   iframe until it's actually wanted (Tom didn't like a mid-sentence YouTube
   thumbnail on the testimony clip). Same .video-embed box, so no layout
   shift when the iframe replaces it. The <a> is the no-JS fallback (a plain
   link to the clip on YouTube); video-facade.js's inline script upgrades it
   to a real <button> and swaps the iframe in on click/Enter/Space. */
.video-facade-link { position: absolute; inset: 0; width: 100%; height: 100%; display: block; border: 0; padding: 0; margin: 0; background: none; cursor: pointer; }
/* r109: beat page photo styles (.story .two-up img tilts + crops 3:4) so the poster always fills its box */
.video-embed.video-facade .video-facade-link img { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; aspect-ratio: auto; object-fit: cover; object-position: center; transform: none; box-shadow: none; border: 0; display: block; }
.video-facade-play { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 3.4rem; height: 3.4rem; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: rgba(13, 13, 13, .72); color: var(--cream); font-size: 1.2rem; padding-left: .18em; /* optical-center the triangle */ transition: background .15s ease, transform .15s ease; }
.video-facade-link:hover .video-facade-play, .video-facade-link:focus-visible .video-facade-play { background: var(--gold); color: var(--black); transform: translate(-50%, -50%) scale(1.06); }
.video-facade-link:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }

/* ---- Photo carousel: scroll-snap strip, the live site's carousel.js drives
   the arrows (loops at the ends). ---- */
.carousel-wrap { position: relative; margin: 1rem 0 1.5rem; }
.carousel-track {
  display: flex; gap: var(--gap-tight); overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; padding: .25rem 0 .75rem;
}
.carousel-track::-webkit-scrollbar { display: none; }
.carousel-track figure { flex: 0 0 82%; scroll-snap-align: start; margin: 0; }
@media (min-width: 640px) { .carousel-track figure { flex-basis: 44%; } }
@media (min-width: 900px) { .carousel-track figure { flex-basis: 30%; } }
.carousel-track img {
  width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover;
  filter: var(--grade-photo); box-shadow: var(--shadow-card);
}
.carousel-track figcaption { font-size: var(--text-caption); color: var(--ink-soft); margin-top: .5rem; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); }
.carousel-btn {
  position: absolute; top: 40%; transform: translateY(-50%); z-index: 2;
  width: var(--btn-icon); height: var(--btn-icon); border: 0; cursor: pointer;
  background: var(--blood); color: var(--cream); font-size: var(--text-h2); line-height: 1;
  box-shadow: var(--shadow-card);
}
.carousel-btn:hover { background: var(--blood-dark); }
.carousel-btn.prev { left: .5rem; } .carousel-btn.next { right: .5rem; } /* inside the wrap: a negative offset was clipped by the section (Mike, round 15) */
.carousel-btn { top: 36%; }
/* r112 (Mike: "the red box stops halfway down"): the ‹ › glyphs sat low and
   spilled out of the box. SVG chevrons, centered with flex. */
.carousel-btn { display: flex; align-items: center; justify-content: center; padding: 0; }
.carousel-btn svg { width: 55%; height: 55%; fill: none; stroke: currentColor; stroke-width: 2.6; stroke-linecap: square; stroke-linejoin: miter; display: block; }

/* ---- Snapshot grid: masonry columns of real photos with a one-line caption. ---- */
.snap-grid { columns: 2; column-gap: var(--gap-tight); }
@media (min-width: 700px) { .snap-grid { columns: 3; } }
@media (min-width: 1100px) { .snap-grid { columns: 4; } }
.snap-item { break-inside: avoid; margin: 0 0 1rem; }
.snap-item img { width: 100%; height: auto; display: block; filter: var(--grade-photo); box-shadow: var(--shadow-card); }
.snap-item figcaption { font-size: var(--text-caption); color: var(--ink-soft); margin-top: .4rem; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); }

/* ---- Story panel: a paper panel with an optional floated photo (the
   testimony / Riding4Him story cards). ---- */
.story { max-width: var(--measure-panel); margin: 0 auto 2rem; }
.story .float { float: right; position: relative; z-index: 1; width: var(--float-w); height: auto; aspect-ratio: 3 / 4; object-fit: cover; margin: .25rem 0 calc(var(--pad-card) + .5rem) var(--float-gutter); transform: rotate(1.4deg); box-shadow: var(--shadow-lift); }
@media (max-width: 699px) { .story .float { float: none; width: 60%; margin: 0 auto 1.25rem; } } /* a 1:3 portrait float wrecked the panel at every width (Fable): capped to 3:4 and cropped, and stacked on phones */
.story .float.square { aspect-ratio: 1 / 1; }
.story figure.float { margin: .25rem 0 var(--pad-card) var(--float-gutter); width: var(--float-w); }
.story figure.float img { width: 100%; height: auto; aspect-ratio: 3 / 4; object-fit: cover; transform: rotate(1.4deg); box-shadow: var(--shadow-lift); }
.story figure.float.small { width: var(--float-w-sm); }
.story figure.float figcaption { font-size: var(--text-caption); color: var(--ink-soft); margin-top: .8rem; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-label); line-height: 1.4; }
.story .two-up { display: grid; grid-template-columns: 1fr; gap: var(--gap-card-row); margin-bottom: 1.5rem; }
@media (min-width: 700px) { .story .two-up { grid-template-columns: 5fr 7fr; align-items: start; } }
.story .two-up figure { margin: 0; }
.story .two-up img { width: 100%; height: auto; aspect-ratio: 3 / 4; object-fit: cover; object-position: center top; transform: rotate(-1.4deg); box-shadow: var(--shadow-lift); }
.story .two-up figcaption { font-size: var(--text-caption); color: var(--ink-soft); margin-top: .8rem; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); }
.story .snap-grid { margin-top: 1.5rem; }
.story .inline-figure { margin: 1.5rem 0 0; max-width: 300px; }
.story .inline-figure img { width: 100%; height: auto; aspect-ratio: 3 / 4; object-fit: cover; object-position: center top; transform: rotate(-1.4deg); box-shadow: var(--shadow-lift); }
.story .inline-figure figcaption { font-size: var(--text-caption); color: var(--ink-soft); margin-top: .6rem; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); }
.story::after { content: ""; display: block; clear: both; }
.story p, .story li { color: var(--ink); font-size: var(--text-body); }
.story .lead { font-size: var(--text-lead); color: var(--ink-soft); }
.story a:not(.btn) { color: var(--blood); } /* .btn is a single class too and content.css loads after base.css, so the plain rule was painting button text blood-on-blood (Fable, review 5) */
.story blockquote { margin: 1.25em 0; padding: .4em 0 .4em 1.2em; border-left: 4px solid var(--gold); font-style: italic; font-weight: 700; color: var(--ink); font-size: var(--text-lead); } /* round 16: bold italic so the quotes stand out */
.story audio { width: 100%; }
.story ol.plain-steps { padding-left: 1.4em; } .story ol.plain-steps li { margin: 0 0 .9em; font-size: var(--text-lead); }
.story blockquote cite { display: block; font-style: normal; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); font-size: var(--text-micro); color: var(--blood); margin-top: .4em; }
.pray .pray-copy p a { color: var(--gold); }

/* ---- Scaffold placeholder: content Tom/Mike still have to supply. Visible
   on the mockup on purpose so nobody mistakes an empty slot for finished.
   Never ships: the build strips nothing, so remove the block when the real
   content lands. ---- */
.todo {
  border: 2px dashed var(--gold); background: var(--paper);
  padding: 1rem 1.25rem; margin: 1.25rem 0; color: var(--ink-soft);
  font-size: var(--text-label);
}
.todo::before {
  content: "Coming"; display: inline-block; margin-right: .75em;
  font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-wide);
  font-size: var(--text-micro); color: var(--blood);
}
.todo strong { color: var(--ink); }

/* ---- Product cards (store): the shot is the whole top (object-fit
   contain so no cover edge is ever cropped), price and link under the
   deck. ---- */
.card.product img { aspect-ratio: 4 / 5; object-fit: cover; background: var(--paper); } /* round 16: product shots fill a taller frame (staged on the official workbench background) */
/* Round 38 (Mobbin: Glossier, Dollar Shave Club, Jasper): a product card is
   photo, name, one quiet line, price, then one full-width outlined button
   pinned to the bottom. The category kicker is gone (the section heading
   already says it); the byline sits under the name in the serif. */
.card.product .card-text { padding: 1.1rem 1.1rem 1.15rem; gap: .3rem; }
.card.product .card-kicker { display: none; }
.card.product .card-title { font-family: "Literata", serif; font-weight: 600; font-size: var(--text-h3); line-height: 1.2; letter-spacing: 0; text-transform: none; }
.card.product .product-by { display: block; font-weight: 400; font-size: var(--text-label); color: var(--ink-soft); margin-top: .1rem; }
.card.product .card-deck { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; font-size: var(--text-label); color: var(--ink-soft); }
/* round 39 (Mike; Mobbin: Loom, Jasper, Shopify Supply): the price is not the name. Name serif 600 at h3; price a small, regular, tracked sans in the soft ink so the eye reads name first, price second. */
.card.product .product-price { font-family: "Literata", serif; font-weight: 400; font-size: var(--text-label); letter-spacing: .04em; color: var(--ink-soft); margin: .3rem 0 0; }
.card.product .product-link { margin: .9rem 0 0; padding-top: 0; }
.card.product .product-link a { display: block; min-height: 48px; line-height: 48px; text-align: center; border: 2px solid var(--ink); color: var(--ink); text-decoration: none; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-btn); font-size: var(--text-micro); transition: background-color .15s ease, color .15s ease; }
.card.product .product-link a:hover, .card.product .product-link a:focus-visible { background: var(--ink); color: var(--cream); }
.card.product .product-link a::after { content: none; }
.card.product.span { grid-column: 1 / -1; } /* round 17: was .wide, which collided with the .wide type utility in base.css */
.card.product.span img { aspect-ratio: 16 / 9; }
@media (min-width: 700px) { .card.product.span { display: grid; grid-template-columns: 3fr 2fr; align-items: center; } .card.product.span img { aspect-ratio: 4 / 3; height: 100%; } }
.card-grid.two { grid-template-columns: 1fr; }
@media (min-width: 700px) { .card-grid.two { grid-template-columns: repeat(2, 1fr); } }
.product-price { font-family: "Archivo Black"; }
.product-by { display: block; font-family: "Literata", serif; text-transform: none; letter-spacing: 0; font-size: var(--text-label); color: var(--ink-soft); }
.product-price { margin: .35rem 0 0; font-size: var(--text-label); color: var(--ink); }
.product-link { margin: .25rem 0 0; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-label); font-size: var(--text-micro); }
.product-link a { color: var(--blood); text-decoration: none; }
.product-link a:hover { text-decoration: underline; }
.panel .btn { margin: .25rem 0 1.5rem; }
.panel h2.slab + h2.slab { margin-top: 2rem; }
@media (min-width: 700px) { .panel .float, .story .float { float: right; } } /* round 16: the picture always sits top right of its card; the markup puts it first. Round 17: this rule had been overriding the phone stack above, leaving headlines in a 40% column; on phones the picture now sits full-width at the top instead. */
@media (max-width: 699px) { .panel .float, .story .float, .story figure.float.small { float: none; width: 100%; max-width: 420px; margin: 0 auto 1.25rem; transform: none; } .story figure.float figcaption { text-align: center; } } /* round 34: .small was still 30% wide on phones (Visitor cover) */
.panel .chapter-num { display: block; margin-bottom: .6rem; color: var(--blood); letter-spacing: var(--track-eyebrow); font-size: var(--text-micro); font-family: "Archivo Black"; text-transform: uppercase; }

/* ---- The closing (shared, every page): moved here from the homepage in
   round 12 when Fable found pages dead-ending. Three next steps, then the
   email. ---- */
/* ---- Closing bookend: watermark bleeds off top and bottom, a stamp
   chip breaks a double rule around the ask. ---- */
/* overflow: hidden added round 6 (Fable caught it): the watermark's
   170%-tall image with max-width:none was pushing the page's own
   scrollWidth wider than the viewport, causing sitewide horizontal
   scroll on mobile -- not just visual overflow inside this section. */
/* Round 9: the same idea as the hero banner (a real leather surface
   with real light on it, the logo reading as part of the material)
   but dialed way down -- this is the quiet close, not the brochure
   moment. A subtle radial glow instead of a bold softbox hotspot, and
   the watermark is a soft-light blend at low opacity so it reads as an
   impression in the leather grain, not a flat translucent sticker. */
.closing-band {
  position: relative; overflow: hidden; color: var(--cream); text-align: center; padding: 5rem var(--page-margin);
  background-image: radial-gradient(ellipse 80% 60% at 35% 15%, var(--glow-soft), transparent 60%), var(--surface-leather-dark);
  background-size: cover, cover, cover;
}
.closing-band .emblem-watermark {
  position: absolute; height: 170%; top: -35%; left: 50%; translate: -50% 0; width: auto;
  max-width: none; opacity: var(--watermark-closing); mix-blend-mode: soft-light; pointer-events: none;
}
.closing-inner { position: relative; z-index: 1; }
.stamp-frame {
  display: inline-block; position: relative; padding: 1.6rem 2.5rem 1.35rem; /* round 30: title centred in the frame (Mike) */
  border: 1px solid var(--gold-line); outline: 1px solid var(--gold-line); outline-offset: 6px;
  margin-bottom: 1.75rem;
}
.stamp-chip {
  position: absolute; top: -6px; left: 50%; transform: translate(-50%, -50%);
  background: var(--black); padding: 0 .75em;
  font-family: "Archivo Black"; font-size: var(--text-micro); letter-spacing: var(--track-wide); color: var(--gold); text-transform: uppercase; white-space: nowrap;
}
.closing-band h2 { font-family: "Anton", sans-serif; font-weight: 400; text-transform: uppercase; color: var(--gold); font-size: var(--text-h2); margin: 0; line-height: 1; }
.closing-band p { max-width: var(--measure-lead); margin: 0 auto 1.75rem; color: var(--cream-soft); font-size: var(--text-lead); }


.next-steps { display: flex; flex-wrap: wrap; gap: .75rem; justify-content: center; margin: 0 0 1.5rem; }
@media (max-width: 599px) { .closing-band .next-steps .btn { width: 100%; max-width: 20rem; justify-content: center; } .btn { white-space: nowrap; } } /* round 21 (Mike): stacked closing buttons share one width */
.closing-email { font-size: var(--text-label); color: var(--cream-faint); }
.closing-email a { color: var(--gold); }
/* Round 27: the forward link is a two-line card (Mobbin: Udemy, Better
   Stack): small "Next" eyebrow, the page name under it, a chevron at right. */
.next-page { margin: 1.5rem 0 0; font-family: "Archivo Black"; text-transform: uppercase; line-height: var(--lh-label); }
.next-page a { display: inline-grid; grid-template-columns: 1fr auto; grid-template-areas: "label arrow" "title arrow"; align-items: center; column-gap: 1rem; min-width: 16rem; padding: .8rem 1.1rem; border: 1px solid var(--gold); color: var(--gold); text-decoration: none; text-align: left; }
.next-page .next-label { grid-area: label; font-size: var(--text-micro); letter-spacing: var(--track-eyebrow); opacity: .8; }
.next-page .next-title { grid-area: title; font-size: var(--text-label); letter-spacing: var(--track-kicker); }
.next-page .next-arrow { grid-area: arrow; font-size: 2em; line-height: 1; }
.next-page a:hover { background: var(--gold); color: var(--black); }

/* ---- The prayer panel (#pray): priority one, made concrete. Tom's own
   written prayer, verbatim from his old site, with two next steps under it.
   Sits on leather red so it reads as the moment, not another card. ---- */
.pray { background-image: var(--surface-leather-red); background-size: cover; color: var(--cream); padding: clamp(3rem, 6vw, 5rem) var(--page-margin); }
.pray-inner { max-width: var(--measure-panel); margin: 0 auto; }
/* Round 13b: the Lesson 24 painting (Jesus beside a biker) sits beside the
   invitation, which is where "Jesus accepts you just as you are" lives now. */
.pray-art { margin: 2rem auto 0; max-width: 420px; }
.pray-art img { width: 100%; height: auto; transform: rotate(1.4deg); box-shadow: var(--shadow-lift); filter: var(--grade-painting); }
@media (min-width: 900px) {
  .pray-inner { max-width: 1200px; display: grid; grid-template-columns: 7fr 5fr; gap: var(--space-panel); align-items: center; }
  .pray-art { margin: 0; max-width: none; }
}
.pray .chapter-num { color: var(--gold); }
.pray h2 { font-family: "Anton", sans-serif; font-weight: 400; text-transform: uppercase; font-size: var(--text-h2); line-height: var(--lh-snug); margin: 0 0 .75rem; color: var(--cream); }
.pray p { color: var(--cream-soft); font-size: var(--text-lead); max-width: var(--measure-lead); }
.pray blockquote { margin: 1.5rem 0; padding: 1.25rem 1.5rem; border-left: 4px solid var(--gold); background: var(--black-veil); font-style: italic; font-size: var(--text-lead); line-height: var(--lh-body); color: var(--cream); }
.pray .next-steps { justify-content: flex-start; }
.btn.gold { background-color: var(--gold); color: var(--black); background-image: radial-gradient(circle at 10px 10px, var(--black) 0 2.5px, transparent 3.5px), radial-gradient(circle at calc(100% - 10px) 10px, var(--black) 0 2.5px, transparent 3.5px), radial-gradient(circle at 10px calc(100% - 10px), var(--black) 0 2.5px, transparent 3.5px), radial-gradient(circle at calc(100% - 10px) calc(100% - 10px), var(--black) 0 2.5px, transparent 3.5px); }
.btn.gold:hover, .btn.gold:focus-visible { background-color: var(--gold-dark); }
.closing-band .next-steps .btn.book { flex-basis: 100%; max-width: 20rem; justify-content: center; } /* round 31 (Mike): booking is a button, not an email sitting in copy; it takes its own row under the three */
.pray .btn { background-color: var(--gold); color: var(--black); background-image: radial-gradient(circle at 10px 10px, var(--black) 0 2.5px, transparent 3.5px), radial-gradient(circle at calc(100% - 10px) 10px, var(--black) 0 2.5px, transparent 3.5px), radial-gradient(circle at 10px calc(100% - 10px), var(--black) 0 2.5px, transparent 3.5px), radial-gradient(circle at calc(100% - 10px) calc(100% - 10px), var(--black) 0 2.5px, transparent 3.5px); } /* Mike, round 15: red buttons on the red leather were invisible */
.pray .btn:hover, .pray .btn:focus-visible { background-color: var(--gold-dark); }
/* Every page carries one Tom quote in a callback band, with his sign-off (Mike, round 15). */
.callback { color: var(--cream); text-align: center; padding: 3rem var(--page-margin); background-image: var(--surface-leather-red); background-size: cover; }
.callback p { font-family: "Anton", sans-serif; text-transform: uppercase; font-size: var(--text-callback); line-height: var(--lh-display); max-width: var(--measure-callback); margin: 0 auto; color: var(--cream); }
.callback .attrib { display: block; margin-top: .75rem; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-eyebrow); font-size: var(--text-micro); color: var(--gold); }

/* Sentence case for long slab headings: Anton uppercase past six words is
   hard on older eyes (Fable, 2026-09-15). */
h2.slab.sentence { text-transform: none; letter-spacing: 0; }

/* Two-minute clip panel at the top of Tom's Story (round 17): the vertical
   YouTube segment sits in the narrow column, text beside it. */
.story.clip .two-up { margin-bottom: 0; }
.story.clip .two-up .video-embed.portrait { max-width: 340px; margin: 0; }
@media (max-width: 699px) { .story.clip .two-up .video-embed.portrait { margin: 0 auto; } }

/* =====================================================================
   Round 22 (2026-09-16): phone patterns from Mobbin + Fable review 11.
   Everything here is scoped under 600px unless noted.
   ===================================================================== */

/* 1. Lesson and sermon cards become rows on phones: art left, title +
   meta right, the audio player tucked under the row and opened by a play
   pill (Apple Podcasts / NYT Audio pattern). Home-page teaser cards and
   product cards are not rows. */
@media (max-width: 599px) {
  .card-grid.lessons .card {
    display: grid; grid-template-columns: 84px 1fr; grid-template-areas: "art title" "art kicker" "play play" "audio audio";
    align-items: center; align-content: center; gap: .15rem .9rem; padding: .6rem .7rem .6rem .6rem; min-height: 96px;
  }
  .card-grid.lessons .card img { grid-area: art; width: 84px; height: 84px; aspect-ratio: 1 / 1; border-radius: 3px; align-self: start; }
  .card-grid.lessons .card-text { display: contents; }
  .card-grid.lessons .card-deck, .card-grid.lessons .card-meta { display: none; }
  .card-grid.lessons .card-title { grid-area: title; font-size: var(--text-h3); line-height: 1.15; align-self: end; }
  .card-grid.lessons .card-kicker { grid-area: kicker; align-self: start; }
  .card-grid.lessons .card .play { grid-area: play; }
  /* the audio row spans under both columns; hidden until the pill opens it */
  .card-grid.lessons .card audio { grid-area: audio; width: 100%; margin: .5rem 0 0; display: none; }
  .card-grid.lessons .card.is-open audio { display: block; }
  .card-grid.lessons .card .play { display: inline-flex; align-items: center; gap: .5rem; min-height: 48px; margin: .35rem 0 0; padding: 0 1rem; border: 0; border-radius: 4px; background: var(--blood); color: var(--cream); font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-btn); font-size: var(--text-btn); cursor: pointer; }
  .card-grid.lessons .card.is-open .play { display: none; }
  .card-grid.lessons .card .play svg { width: 1em; height: 1em; fill: currentColor; }
  .card-grid.lessons .episode.featured { display: flex; flex-direction: column; }
  .card-grid.lessons .episode.featured .card-text { display: flex; }
  .card-grid.lessons .episode.featured img { width: 100%; height: auto; aspect-ratio: 16 / 9; }
  .card-grid.lessons .episode.featured .card-text { padding: 1rem 1.1rem; }
  .card-grid.lessons .episode.featured .card-deck { display: block; }
  .card-grid.lessons .episode.featured audio { display: block; margin: .25rem 1.1rem 1rem; }
  .card-grid.lessons .episode.featured .play { display: none; }

  /* 2. The subject list turns into a sticky chip strip so he can jump
     back from lesson 19 without scrolling 30,000px. */
  .jump { position: sticky; top: 0; z-index: 20; flex-wrap: nowrap; overflow-x: auto; gap: .5rem; margin: 0 calc(-1 * var(--page-margin)) 2rem; padding: .6rem var(--page-margin); background: var(--cream); box-shadow: 0 2px 6px rgba(0,0,0,.12); scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .jump::-webkit-scrollbar { display: none; }
  .jump-label { display: none; }
  .jump a { flex: 0 0 auto; min-height: 48px; display: inline-flex; align-items: center; padding: 0 1rem; font-size: var(--text-micro); line-height: var(--lh-label); }
  .jump a.is-current { background: var(--gold); border-color: var(--gold); color: var(--black); }

  /* 3. Store: two products per row, photo + name + price, deck hidden
     (Apple Store / NYT Cooking). The wide banner/mat cards stay full width. */
  .card-grid:has(.card.product) { grid-template-columns: repeat(2, 1fr); gap: .75rem; }
  /* round 36 (Mobbin: Apple Store, Instacart, SHEIN): on a phone a product
     card is photo, name, price. Name in the serif at body size, price bold
     under it, the kicker gone, the order link a plain small line. */
  .card.product .card-deck, .card.product .product-by { display: none; }
  .card.product .card-text { padding: .7rem .7rem .8rem; gap: .2rem; }
  .card.product .card-title { font-size: var(--text-label); }
  .card.product .product-price { font-size: var(--text-micro); margin: .15rem 0 0; }
  .card.product .product-link { margin-top: .6rem; }
  .card.product .product-link a { min-height: 44px; line-height: 44px; white-space: nowrap; font-size: clamp(10px, 2.9vw, 13px); letter-spacing: .02em; padding: 0 .3rem; }
  .card.product.span { grid-column: 1 / -1; }

  /* round 36: category strip = round thumbnails with the label under
     them, scrolling sideways (Instacart / Zip / SHEIN), not five tiles with
     text over the photo and an orphan. */
  .cat-grid { display: flex; gap: 1rem; overflow-x: auto; padding: .25rem var(--page-margin) .75rem; margin: 0 calc(-1 * var(--page-margin)); scrollbar-width: none; }
  .cat-grid::-webkit-scrollbar { display: none; }
  .cat { flex: 0 0 auto; width: 100px; aspect-ratio: auto; overflow: visible; box-shadow: none; text-align: center; }
  .cat img { display: none; }
  .cat .cat-icon { position: static; display: flex; align-items: center; justify-content: center; width: 84px; height: 84px; margin: 0 auto; padding: 0; border-radius: 50%; background: var(--black); box-shadow: var(--shadow-card); }
  .cat .cat-icon svg { width: 40px; height: 40px; fill: none; stroke: var(--gold); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
  .cat span:not(.cat-icon) { position: static; display: block; padding: .5rem 0 0; background: none; color: var(--ink); font-family: "Literata", serif; font-weight: 500; text-transform: none; letter-spacing: 0; font-size: var(--text-label); line-height: 1.2; white-space: normal; }

  /* 4. No button may push the page sideways. */
  .btn { white-space: normal; max-width: 100%; box-sizing: border-box; text-align: center; justify-content: center; }
  .panel .btn, .group .btn { width: 100%; }

  /* 6. Tap targets: every text link that acts as a control gets 48px. */
  .closing-email a, .hero-link, .story a:not(.btn), .todo a { display: inline-block; min-height: 48px; padding-block: .6rem; }

  /* 8. The forward path is a real button at the bottom. */
  .next-page a { display: grid; width: 100%; max-width: 20rem; margin: 0 auto; padding: .9rem 1.1rem; background: transparent; color: var(--gold); border: 2px solid var(--gold); } /* round 32 (Mike): stroke, not fill; a gold box under the gold Book button was two yellows stacked */

  /* 9. The marquee is unreadable at phone size and eats the first screen. */
  .ticker { display: none; }
}

/* 5. Poem: the verse gets its own backing so the last stanza stays legible
   over the road (any width where the veil thins). */
@media (max-width: 799px) {
  /* round 28 (Mike): the backing has no hard edge; it is a radial pool
     behind the verse that fades to nothing at the edges */
  .poem-text { position: relative; z-index: 0; padding: 1.4rem 1.5rem; background: none; }
  .poem-text::before {
    content: ""; position: absolute; z-index: -1; inset: -1.5rem -1rem; background: rgba(13,13,13,.45); /* round 30: 15% lighter; round 38: 15% lighter again */
    -webkit-mask-image: linear-gradient(to right, transparent, #000 18%, #000 82%, transparent), linear-gradient(to bottom, transparent, #000 12%, #000 88%, transparent);
            mask-image: linear-gradient(to right, transparent, #000 18%, #000 82%, transparent), linear-gradient(to bottom, transparent, #000 12%, #000 88%, transparent);
    -webkit-mask-composite: source-in; mask-composite: intersect;
  }
}

/* Round 33 (Mike): on phones the only tilted thing is the hero patch; every
   other photo sits square. The 1.4deg "polaroid" tilt stays on desktop. */
@media (max-width: 699px) {
  .page-hero-art img, .panel-grid img, .story .float, .story figure.float img, .story .two-up img, .story .inline-figure img, .pray-art img, .patch-grid img { transform: none; }
}

/* round 40 (Mike, universal): every all-caps selector in this file set solid. */
.callback .attrib,
.callback p,
.card-grid.lessons .card .play,
.card-kicker,
.card.product .product-link a,
.carousel-track figcaption,
.cat span,
.closing-band h2,
.jump a,
.jump-label,
.next-page,
.page-hero h1,
.page-hero-eyebrow,
.panel .chapter-num,
.pray h2,
.product-link,
.read-back,
.read-body .closing,
.read-body cite,
.read-body h2,
.read-body h3,
.read-nav a,
.snap-item figcaption,
.stamp-chip,
.story .inline-figure figcaption,
.story .two-up figcaption,
.story blockquote cite,
.story figure.float figcaption,
.todo::before { line-height: var(--lh-caps); }

/* round 45 (Mike, universal, all projects): anything that looks like a button
   centres its text vertically, whatever the line-height. Flex, not line-height tricks. */
.btn, .card.product .product-link a, .card .play, .product-link a { display: inline-flex; align-items: center; justify-content: center; }
.card.product .product-link a { display: flex; line-height: var(--lh-caps); }

/* round 48 (Mike; Mobbin: AI in Design Report "01 Tools", Webflow chapter eyebrow,
   Cofounder chapter cards): the chapter label is a number tile plus a one-line
   kicker, not a sentence that wraps. On phones the painting sits beside the tile
   and heading (IKEA / Dropbox article rows) so a chapter is shorter to scan
   without shrinking the body text. */
.panel .chapter-num { display: flex; align-items: center; gap: .6rem; min-width: 0; }
.panel .chapter-num .ch-n { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 2.1em; height: 2.1em; background: var(--black); color: var(--gold); font-family: "Anton", sans-serif; font-size: 1.25em; letter-spacing: .02em; line-height: var(--lh-caps); }
.panel .chapter-num .ch-t { min-width: 0; line-height: var(--lh-caps); }
@media (max-width: 699px) {
  /* kicker row first, full width; then the painting floats left at 45% with the
     heading and the opening text wrapping beside and under it (newspaper cut). */
  .story:has(> .float), .story:has(> .ch-body > .float), .ch-body { display: flow-root; }
  .story:has(> .float) > .chapter-num { margin: 0 0 .8rem; }
  .story:has(> .float) > .float, .story .ch-body > .float { float: left; width: 45%; max-width: none; margin: .15rem var(--gap-tight) .4rem 0; aspect-ratio: 1 / 1; }
  .story:has(> .float) > h2.slab, .story:has(> .ch-body > .float) > h2.slab { margin: 0 0 .8rem; } /* round 49 (Mike): heading full width above the picture; only the text wraps beside it */
  .panel + .panel { margin-top: 1.25rem; }
}

/* round 50 (Mike): on phones a chapter shows its heading, picture and the first
   lines, then a Read more button; the rest unfolds in place. Desktop shows it all. */
.ch-more { display: none; }
@media (max-width: 699px) {
  .story:has(> .ch-body) > .ch-body { position: relative; max-height: 15.5rem; overflow: hidden; }
  .story:has(> .ch-body) > .ch-body::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 4rem; background: linear-gradient(to bottom, transparent, var(--paper)); pointer-events: none; }
  .story.is-open > .ch-body { max-height: none; }
  .story.is-open > .ch-body::after { content: none; }
  .story:has(> .ch-body) > .ch-more { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; margin: .5rem 0 0; padding: 0 1.1rem; border: 2px solid var(--ink); background: transparent; color: var(--ink); font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-btn); font-size: var(--text-micro); line-height: var(--lh-caps); cursor: pointer; }
}

/* round 51 (Mike): the prayer chapter is red like the homepage prayer card. */
.panel.red { background: var(--surface-leather-red); background-size: cover; color: var(--cream); }
.panel.red::before { border-color: var(--gold-line); }
.panel.red .chapter-num, .panel.red .chapter-num .ch-t { color: var(--gold); }
.panel.red .chapter-num .ch-n { background: var(--black); }
.panel.red h2.slab { color: var(--cream); border-color: var(--gold-line); }
.panel.red p, .panel.red p.lead { color: var(--cream-soft); }
.panel.red p strong { color: var(--cream); }
.panel.red blockquote { padding: 1.25rem 1.5rem; border-left: 4px solid var(--gold); background: var(--black-veil); color: var(--cream); }
.panel.red .ch-body::after { background: linear-gradient(to bottom, transparent, var(--blood)); }
/* round 54 (Mike): the prayer breathes, three paragraphs, homepage and Pray page identical. */
.pray blockquote p, .panel.red blockquote p { margin: 0 0 .9em; color: inherit; font-size: inherit; }
.pray blockquote p:last-child, .panel.red blockquote p:last-child { margin-bottom: 0; }

/* round 58 (Mike): on the Pray page the paintings go back to full width on phones
   (the prayer card keeps its 45% float) and each chapter shows about 200 words
   before Read more. */
@media (max-width: 699px) {
  .story.art-wide .ch-body > .float { float: none; width: 100%; margin: .2rem 0 1rem; } /* round 62: Riding4Him takes the Pray card style */
  .story.art-wide .ch-body > img.float:not(.square) { aspect-ratio: 4 / 3; }
  .story.art-wide .ch-body > figure.float img { height: 77vw; width: auto; max-width: 100%; aspect-ratio: 3 / 4; object-fit: cover; display: block; margin: 0 auto; transform: none; }
  .story.art-wide .ch-body > figure.float { float: none; width: 100%; margin: .2rem 0 1rem; }
  .story.art-wide > .ch-body { max-height: calc(77vw + 15rem); }
  .story.art-wide > .ch-body:has(> img.float:not(.square)) { max-height: calc(58vw + 15rem); } /* round 59 (Mike): the picture plus a few lines, then Read more on every chapter */
}
.story.no-fold > .ch-body { max-height: none; } .story.no-fold > .ch-body::after { content: none; } .story.no-fold > .ch-more { display: none; }
@media (max-width: 699px) { .story > .ch-body::after { height: 2.5rem; } } /* round 60 (Mike): the fade was eating the lines; five clear lines before it */

/* round 61 (Mike): order buttons sit on the card's bottom edge in every row;
   a product with no link yet gets a quiet dashed box, not loose text. */
.card.product .product-link { margin-top: auto; padding-top: .9rem; }
.card.product .product-link .soon { display: flex; align-items: center; justify-content: center; min-height: 48px; border: 2px dashed var(--ink-soft); color: var(--ink-soft); font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-btn); font-size: var(--text-micro); line-height: var(--lh-caps); text-align: center; padding: 0 .5rem; }
@media (max-width: 699px) { .card.product .product-link .soon { min-height: 44px; font-size: clamp(10px, 2.9vw, 13px); letter-spacing: .02em; } }
@media (min-width: 700px) { .card.product.span { align-items: stretch; } .card.product.span .card-text { justify-content: center; } } /* round 61: wide cards keep the button on the bottom edge like the rest */

/* round 67 (Mike, Testimony cleanup): a square video box; the shadow on a
   floated figure belongs to its picture, not to the caption. */
.video-embed.square { aspect-ratio: 1 / 1; max-width: none; }
.story figure.float { box-shadow: none; transform: none; }
@media (max-width: 699px) { .story.art-wide > .ch-body:has(> figure.float) { max-height: calc(77vw + 19rem); } } /* round 67: a captioned figure needs room for its caption plus the five lines */

/* ---- round 70: merch quick view (Mobbin: Shopify Supply quick view, Duolingo
   shop details, NEON info). Tap a product, a sheet slides up with photo,
   name, price, sizes, colour, base garment, one spec line, one Buy button and
   the honest shipping lines. Bottom sheet on phones, centred card on desktop.
   The card photo is itself the button. ---- */
.card.product .card-open { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: pointer; }
.card.product .card-open img { display: block; }
.card.product .product-link .qv-open { width: 100%; }
.qv { border: 0; padding: 0; background: var(--paper); color: var(--ink); max-width: min(92vw, 560px); width: 100%; box-shadow: var(--shadow-lift); }
.qv::backdrop { background: rgba(13, 13, 13, .72); }
.qv[open] { display: grid; grid-template-columns: 1fr; }
.qv > .qv-media { display: flex; flex-direction: column; min-height: 0; }
.qv > .qv-media > img.qv-main { width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: cover; display: block; filter: var(--grade-card); }
/* round 94: product gallery thumbnails inside the quick view. Tap a thumb, the
   main photo swaps in place; each thumb is a real button (keyboard + focus-visible). */
.qv-thumbs { display: flex; gap: .5rem; padding: .6rem .75rem; overflow-x: auto; background: var(--paper); flex: 0 0 auto; }
.qv-thumb { flex: 0 0 auto; width: 48px; height: 48px; min-width: 44px; min-height: 44px; padding: 0; border: 2px solid transparent; border-radius: 6px; background: none; cursor: pointer; overflow: hidden; -webkit-tap-highlight-color: transparent; }
.qv-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; filter: var(--grade-card); }
.qv-thumb.is-active { border-color: var(--gold); }
.qv-thumb:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }
.qv-close-form { position: absolute; top: .5rem; right: .5rem; margin: 0; z-index: 2; }
.qv-close { width: 44px; height: 44px; border: 0; border-radius: 50%; background: var(--black); color: var(--cream); font-size: 1.6rem; line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.qv-body { padding: 1.1rem 1.25rem 1.5rem; display: flex; flex-direction: column; gap: .5rem; }
.qv-title { font-family: "Literata", serif; font-weight: 600; font-size: var(--text-h3); line-height: 1.15; margin: 0; }
.qv-price { font-family: "Literata", serif; font-size: var(--text-lead); color: var(--ink); margin: 0; }
.qv-specs { display: grid; grid-template-columns: auto 1fr; gap: .25rem 1rem; margin: .5rem 0 0; font-size: var(--text-label); }
.qv-specs dt { font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-label); font-size: var(--text-micro); color: var(--ink-soft); line-height: var(--lh-caps); align-self: center; }
.qv-specs dd { margin: 0; color: var(--ink); }
.qv-spec { color: var(--ink-soft); font-size: var(--text-label); margin: .25rem 0 0; }
.qv-buy { margin: .75rem 0 .25rem; width: 100%; }
.qv-buy-list { display: flex; flex-direction: column; gap: .4rem; margin: .75rem 0 .25rem; }
.qv-buy-list .qv-buy { margin: 0; padding: .6rem 1rem; font-size: var(--text-micro); letter-spacing: var(--track-label); white-space: normal; text-align: center; }
.qv-ship { list-style: none; margin: .5rem 0 0; padding: .75rem 0 0; border-top: 1px solid var(--gold-line); color: var(--ink-soft); font-size: var(--text-micro); display: grid; gap: .3rem; }
.qv-fine { color: var(--ink-soft); font-size: var(--text-micro); margin: .25rem 0 0; }
@media (max-width: 699px) {
  .qv { max-width: none; width: 100vw; margin: auto 0 0; max-height: 92dvh; overflow: auto; border-radius: 14px 14px 0 0; }
  .qv > .qv-media > img.qv-main { aspect-ratio: 4 / 3; }
  .qv[open] { animation: qv-up .28s ease-out; }
  @keyframes qv-up { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
}
@media (min-width: 700px) {
  .qv { margin: auto; max-height: 90vh; overflow: auto; }
  .qv[open] { grid-template-columns: 1fr 1fr; align-items: start; }
  .qv > .qv-media { height: 100%; }
  .qv > .qv-media > img.qv-main { height: auto; max-height: 70vh; aspect-ratio: auto; flex: 1 1 auto; min-height: 0; }
}

/* ---- round 102 (launch prep): "Coming soon" die-cut sticker for merch and
   digital downloads whose checkout isn't live yet (Printful checkout off,
   Payhip payouts not connected). One reusable badge, pinned to the image's
   top-left corner on a card and in its quick view. Left, not right, so it
   still sits over the photo on the wide banner card (image/text sit
   side-by-side there, not stacked). ---- */
.coming-soon-sticker {
  position: absolute; z-index: 2; top: .55rem; left: .55rem;
  display: flex; align-items: center; justify-content: center; text-align: center;
  width: 4.4rem; height: 4.4rem; border-radius: 50%;
  background: var(--black); border: 2px solid var(--gold);
  box-shadow: 0 3px 8px rgba(0,0,0,.5);
  transform: rotate(-8deg); pointer-events: none;
  font-family: "Anton", sans-serif; font-weight: 400; text-transform: uppercase;
  line-height: 1; padding: .25rem;
}
.coming-soon-sticker .l1 { display: block; color: var(--cream); font-size: clamp(.58rem, 1.5vw, .72rem); }
.coming-soon-sticker .l2 { display: block; color: var(--gold); font-size: clamp(.66rem, 1.7vw, .84rem); margin-top: .08em; }
.qv-media { position: relative; }
.qv-buy-soon { margin: .75rem 0 .25rem; padding: .75rem 1rem; border: 2px dashed var(--ink-soft); color: var(--ink-soft); font-size: var(--text-label); text-align: center; }
.qv-buy-soon a { color: var(--ink); font-weight: 600; }

/* round 75 (Fable): visible keyboard focus on the store's tappable pictures, detail buttons and the sheet's close; muted build stamp. */
.card.product .card-open:focus-visible img, .qv-open:focus-visible, .qv-close:focus-visible, .ch-more:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }
/* r105 (a11y audit): the Bible Studies play pill had no focus ring at all. */
.card-grid.lessons .card .play:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }
.qv-title:focus { outline: none; }

/* ---- round 77: fixes from the five-lens review ---- */
.story.is-open > .ch-body, .story.art-wide.is-open > .ch-body { max-height: none !important; } /* Read more was dead on art-wide chapters: the open rule lost specificity to the art-wide max-height */
.story.is-open > .ch-body::after { content: none !important; }
.story:not(.is-open) > .ch-body a, .story:not(.is-open) > .ch-body button { visibility: hidden; } /* nothing focusable hides under the fold */
.story.no-fold > .ch-body a, .story.no-fold > .ch-body button { visibility: visible; }
@media (min-width: 600px) { .card-grid.lessons .card .play { display: none; } } /* the phone play pill leaked to tablet/desktop as an unstyled button */
.card-grid:has(.card.product), .card-grid.two { grid-template-columns: repeat(2, minmax(0, 1fr)); } /* equal columns: nowrap button labels were widening one column */
@media (max-width: 699px) { .card-grid:has(.card.product) { grid-template-columns: repeat(2, minmax(0, 1fr)); } .card.product .product-link a { white-space: normal; } }
@media (min-width: 700px) { .card-grid:has(.card.product) { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); } }
h2.slab.sentence { line-height: var(--lh-snug); } /* sentence-case slabs are mixed case, so the all-caps solid rule does not apply to them */
.snap-item img { aspect-ratio: 4 / 3; object-fit: cover; } /* masonry photos no longer jump from 0 height as they load */
.ticker:hover .ticker-track, .ticker:focus-within .ticker-track { animation-play-state: paused; }

/* ---- Round 78 (Tom's photo drop, 2026-09-19): Cathy at the piano under
   the music video on the homepage. Same photo treatment as the patch grid. ---- */
.music-photo { margin: 1.25rem 0 0; }
.music-photo img { width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; }
.music-photo figcaption { font-size: var(--text-caption); color: var(--ink-soft); margin-top: .6rem; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); line-height: var(--lh-caps); }

/* Round 79/80: no global object-position. Photos that need a specific crop
   are pre-cropped files in assets/img/tc26 (Mike: the site-wide top anchor
   was cutting the subject out of previously placed photos). */

/* ---- round 104 (Mike, launch): a search committee reviewing Tom for a
   pastor job saw a wall of eight "Coming soon" stickers and read it as an
   abandoned site. The Garage Collection grid collapses (SHOW_MERCH=False in
   build-pages.py) to one calm strip: a few photos, one line, one email link,
   one sticker. Also: a booking-honorarium note under "Book Tom & Cathy",
   and a Support the ministry block/link (store, Pray, footer). ---- */
.merch-soon { position: relative; display: flex; flex-direction: column; gap: 1rem; padding: 1.5rem; background: var(--paper); border: 1px solid var(--gold-line); }
.merch-soon-photos { display: flex; gap: .6rem; flex-wrap: wrap; }
.merch-soon-photos img { width: 84px; height: 84px; object-fit: cover; border-radius: 6px; filter: var(--grade-card); flex: 0 0 auto; }
.merch-soon-text { display: flex; flex-direction: column; gap: .5rem; }
.merch-soon-text .card-title { margin: 0; }
.merch-soon-text p { margin: 0; color: var(--ink-soft); }
.merch-soon-text .btn { align-self: flex-start; margin-top: .25rem; }
@media (min-width: 700px) { .merch-soon { flex-direction: row; align-items: center; } .merch-soon-photos { flex: 0 0 auto; } }

.closing-band p.booking-note { max-width: var(--measure-lead); margin: -.75rem auto 1.25rem; color: var(--cream-faint); font-size: var(--text-micro); }

.give-fine { color: var(--ink-soft); font-size: var(--text-micro); margin: .35rem 0 0; }
#give, section.group#give-pray { background: var(--paper); border: 1px solid var(--gold-line); padding: 1.5rem; margin: 1.5rem 0; }
footer.site-foot a + a { margin-left: .35rem; }

/* r112 (Mike): Cathy's chapter. Text at the top of the right column, a 2x2
   of her photos pinned to the bottom so they line up with the piano photo. */
@media (min-width: 700px) {
  .story .two-up.with-side { align-items: stretch; }
  .story .two-up.with-side > div { display: flex; flex-direction: column; }
  .story .two-up.with-side .side-snaps { margin-top: auto; }
}
.snap-grid.side-snaps { columns: auto; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 1.5rem; gap: var(--gap-tight); }
.snap-grid.side-snaps .snap-item { margin: 0; }
.story .two-up.with-side .side-snaps img { aspect-ratio: 1 / 1; transform: none; box-shadow: var(--shadow-card); } /* square: taller, keeps faces in the selfies */

/* r112 (Mike): the signing photo leads the Books group, big, beside the blurb. */
.group-lead { display: grid; grid-template-columns: 1fr; gap: var(--gap-grid); align-items: center; margin-bottom: var(--space-panel); }
@media (min-width: 800px) { .group-lead { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); } }
.group-lead .group-blurb { margin: 0; }
.group-photo { margin: 0; }
.group-photo img { width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; box-shadow: var(--shadow-lift); filter: var(--grade-photo); display: block; }
.group-photo figcaption { font-size: var(--text-caption); color: var(--ink-soft); margin-top: .6rem; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); }

/* r112 (Mike: "need vertical space between rows, check sitewide"): any two
   stacked media rows (photo grid, video row, card grid, two-up) get a real gap. */
:is(.snap-grid, .video-row, .card-grid, .two-up, .group-lead, .video-embed) + :is(.snap-grid, .video-row, .card-grid, .two-up, .video-embed) { margin-top: var(--space-row); }
@media (min-width: 1000px) { .snap-grid.side-snaps { grid-template-columns: repeat(3, minmax(0, 1fr)); } } /* one bottom row of three beside the piano photo */

/* r112 (Mike: the play button sat on Tom's belt): tall videos are full-body
   shots, so their play button goes in the lower-left corner, over the ground. */
.video-embed.portrait .video-facade-play { top: auto; left: 1rem; bottom: 1rem; transform: none; }
.video-embed.portrait .video-facade-link:hover .video-facade-play,
.video-embed.portrait .video-facade-link:focus-visible .video-facade-play { transform: scale(1.06); }

/* r112 (Mike): a headline phrase that must stay on one line on desktop ("to Sixty Years"). */
@media (min-width: 800px) { .page-hero h1 .keep { white-space: nowrap; } }

/* r112 (Mike): one photo shown big, uncropped (the helmet stickers are text,
   so no strip crop). Centered, native aspect, leads its gallery. */
.feature-photo { margin: 0 auto var(--space-row); max-width: min(100%, 1000px); }
.feature-photo img { width: 100%; height: auto; display: block; box-shadow: var(--shadow-lift); filter: var(--grade-photo); }
.feature-photo figcaption { font-size: var(--text-caption); color: var(--ink-soft); margin-top: .6rem; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); }

/* r113 (Mike): Hear It From Tom, the two cards on the left and the big helmet
   photo filling the right half (native 4:3, uncropped: the stickers are text). */
.hear-grid { display: grid; grid-template-columns: 1fr; gap: var(--gap-grid); align-items: center; }
@media (min-width: 1000px) { .hear-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
.hear-photo { margin: 0; }
.hear-photo img { width: 100%; height: auto; display: block; box-shadow: var(--shadow-lift); filter: var(--grade-photo); transform: rotate(-1.4deg); } /* same print tilt as the other lifted photos */
.hear-photo figcaption { font-size: var(--text-caption); color: var(--ink-soft); margin-top: .8rem; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); }
@media (prefers-reduced-motion: reduce) { .hear-photo img { transform: none; } }

/* r113 (Mike): captions under video rows (Part 1, Part 2...) match the bold all-caps photo captions. */
.video-row .video-caption { text-align: left; font-size: var(--text-caption); color: var(--ink-soft); margin-top: .6rem; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-kicker); line-height: var(--lh-caps); text-wrap: pretty; }

/* r114 (Mike): the patch card sat on the merch block's gold border. Space below the merch block. */
.merch-soon + .card-grid { margin-top: var(--space-row); }
/* The quick-view "See details" button was an unstyled browser button; same outlined button as the store's product links. */
.card.product .product-link .qv-open { display: flex; align-items: center; justify-content: center; width: 100%; min-height: 48px; padding: 0 .5rem; background: none; border: 2px solid var(--ink); border-radius: 0; color: var(--ink); cursor: pointer; font-family: "Archivo Black"; text-transform: uppercase; letter-spacing: var(--track-btn); font-size: var(--text-micro); line-height: var(--lh-caps); transition: background-color .15s ease, color .15s ease; }
.card.product .product-link .qv-open:hover, .card.product .product-link .qv-open:focus-visible { background: var(--ink); color: var(--cream); }
.group-lead-text p { margin: 0 0 1rem; color: var(--ink-soft); max-width: var(--measure-lead); }
.group-lead .group-lead-text .group-blurb { margin: 0 0 1.25rem; } /* the .group-lead .group-blurb {margin:0} rule ran the paragraphs together */
.group-lead-text p:last-child { margin-bottom: 0; }

/* r115 (Mike): the photos above the videos in Hear Them Play read as video links. Videos come first; the two photos follow as a plain 2-up. */
.snap-grid.two-photos { columns: auto; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-tight); }
.snap-grid.two-photos .snap-item { margin: 0; }
