/* Sweet Streaks — the app's own design system, translated to the web.
   Every value below is lifted from the app: Theme.swift colors (hex-exact), sharp
   corners (Radius: "suits the pixel art"), chunky borders with hard offset shadows
   (woodPanel), Press Start 2P on the display tier and rounded type everywhere else. */

:root {
  --bg:            #B99C6B;   /* Background — warm wheat-tan canvas */
  --surface:       #F0E3C2;   /* CardBackground — parchment panel */
  --ink:           #241708;   /* TextPrimary — warm espresso */
  --ink-soft:      #6E5636;   /* TextSecondary — warm taupe */
  --border:        #4A2E17;   /* PanelBorder — wood-brown edge */
  --primary:       #9C4426;   /* AccentOrange — burnt orange */
  --gold:          #D2A63F;
  --sage:          #4F6B41;
  --shadow:        rgba(66, 45, 26, 0.55);
  /* THE width system. Three tokens, one breakpoint (760px). Nothing else. */
  --page:  1200px;   /* every page container */
  --panel: 1000px;   /* every parchment panel (legal, articles) */
  --prose: 68ch;     /* every paragraph measure */
  --pixel: "Press Start 2P", monospace;
  --round: "Nunito", -apple-system, "SF Pro Rounded", sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  overflow-x: clip;   /* nothing may ever cause a horizontal scroll */
  background: var(--bg);
  color: var(--ink);
  font-family: var(--round);
  font-size: 17px;
  line-height: 1.55;
}

/* ── The entrance ─────────────────────────────────────────────────────────────────
   The temple-ride moment: torch-dark cave mouth, the wordmark catching light, then
   the doors part onto the parchment world. Plays once per session; a tap skips it;
   reduced-motion goes straight inside. */
#entrance {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  background: #16100a;
  overflow: hidden;
  cursor: pointer;
}
#entrance .cave {
  position: absolute; inset: -6%;
  background: url("assets/world_cave.png") center 30% / cover no-repeat;
  image-rendering: pixelated;
  filter: brightness(0.45) saturate(0.9);
  animation: cave-approach 9s ease-out forwards;
}
#entrance .torchlight {
  position: absolute; inset: 0;
  background:
    radial-gradient(38% 30% at 26% 42%, rgba(255, 170, 60, 0.32), transparent 70%),
    radial-gradient(34% 28% at 74% 40%, rgba(255, 150, 40, 0.28), transparent 70%);
  mix-blend-mode: screen;
  animation: flicker 0.42s steps(2) infinite;
}
#entrance .mark {
  position: relative; width: min(52vw, 340px);
  image-rendering: pixelated;
  filter: drop-shadow(3px 4px 0 rgba(0,0,0,0.6));
  animation: mark-rise 2.0s ease-out forwards;
}
#entrance .gate {
  position: relative; display: grid; place-items: center; gap: 26px;
}
#entrance .dare {
  font-family: var(--pixel); font-size: 10px; letter-spacing: 2px;
  color: rgba(240, 227, 194, 0.75);
  text-shadow: 2px 2px 0 rgba(0,0,0,0.7);
  animation: hint-in 0.8s ease 0.9s both;
}
#entrance .enter {
  font-size: 13px; padding: 16px 34px;
  cursor: pointer;
  animation: hint-in 0.8s ease 1.1s both;
}
#entrance .enter:hover { filter: brightness(1.12); }
#entrance.skip { animation: doors-part 0.55s ease-in forwards; }

/* Slow enough that the hold at the threshold never visibly freezes. */
@keyframes cave-approach { from { transform: scale(1); } to { transform: scale(1.22); } }
@keyframes flicker { 0% { opacity: 0.75; } 50% { opacity: 1; } 100% { opacity: 0.85; } }
@keyframes mark-rise {
  from { transform: translateY(26px); opacity: 0; }
  35%  { opacity: 1; }
  to   { transform: translateY(0); opacity: 1; }
}
@keyframes hint-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes doors-part { to { clip-path: inset(0 50% 0 50%); visibility: hidden; } }

@media (prefers-reduced-motion: reduce) {
  #entrance { display: none; }
}

/* ── Chrome ──
   No navigation until it's needed: the hero IS the header (logo + one button,
   centered, Foreword-style). The bar slides in only after the hero scrolls away —
   and on parchment it wears the burnt-orange wordmark, because the yellow one
   belongs on dark ground (the same lesson the app's share cards learned). */
header.site {
  /* above everything except the entrance/cutscene overlays */
  position: fixed; top: 0; left: 0; right: 0; z-index: 60;
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px clamp(16px, 4vw, 40px);
  background: var(--surface);
  border-bottom: 3px solid var(--border);
  transform: translateY(-110%);
  transition: transform 0.28s ease;
}
header.site.shown { transform: translateY(0); }
header.site img { height: 34px; image-rendering: pixelated; }
/* Legal pages keep a resting header — there's no hero to carry the load. */
header.site.static { position: sticky; transform: none; transition: none; }
.btn {
  display: inline-block;
  font-family: var(--pixel); font-size: 11px;
  padding: 12px 18px;
  color: #fff; background: var(--primary);
  border: 3px solid var(--border);
  box-shadow: 3px 4px 0 var(--shadow);
  text-decoration: none;
  transition: transform 0.1s ease, box-shadow 0.1s ease, filter 0.1s ease;
}
/* hover lifts the button off the wood; active presses it into its shadow */
.btn:hover { transform: translate(-2px, -3px); box-shadow: 5px 7px 0 var(--shadow); filter: brightness(1.07); }
.btn:active { transform: translate(2px, 3px); box-shadow: 1px 1px 0 var(--shadow); filter: none; }
.btn.quiet { background: var(--surface); color: var(--ink); }

/* ── Hero ── */
.hero {
  position: relative;
  min-height: 78vh;
  display: grid; place-items: center;
  text-align: center;
  padding: 8vh 20px 10vh;
  background: url("assets/cs_temple_midday_open.png") center 42% / cover no-repeat;
  image-rendering: pixelated;
  border-bottom: 4px solid var(--border);
  overflow: hidden;
}
.hero::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(rgba(22,16,10,0.30), rgba(22,16,10,0.68));
}
.hero > div { position: relative; z-index: 1; }
.hero > div:not(.gems) { z-index: 2; }
.hero img.mark { width: min(70vw, 420px); image-rendering: pixelated;
                 filter: drop-shadow(3px 4px 0 rgba(0,0,0,0.55)); }
.hero h1 {
  font-family: var(--pixel); font-size: clamp(14px, 2.6vw, 22px);
  color: #F0E3C2; text-shadow: 3px 3px 0 rgba(0,0,0,0.6);
  margin-top: 28px; line-height: 1.8;
}
.hero p.sub {
  color: #F0E3C2; opacity: 0.92; max-width: 560px; margin: 18px auto 30px;
  font-size: 18px; text-shadow: 1px 2px 0 rgba(0,0,0,0.5);
}

/* ── Sections ── */
main { max-width: var(--page); margin: 0 auto; padding: 0 clamp(16px, 4vw, 40px); }
section.feature {
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(24px, 5vw, 64px);
  align-items: center;
  padding: clamp(48px, 8vw, 96px) 0;
}
section.feature:nth-of-type(even) .art { order: -1; }
@media (max-width: 760px) {
  section.feature { grid-template-columns: 1fr; }
  section.feature .art { order: -1 !important; }
}
.kicker {
  font-family: var(--pixel); font-size: 11px; letter-spacing: 1px;
  color: var(--primary); text-transform: uppercase;
}
section h2 {
  font-family: var(--pixel); font-size: clamp(15px, 2.2vw, 20px);
  line-height: 1.7; margin: 12px 0 16px;
}
section p { color: var(--ink-soft); max-width: var(--prose); }
section p strong { color: var(--ink); }

.panel {
  background: var(--surface);
  border: 3px solid var(--border);
  box-shadow: 4px 5px 0 var(--shadow);
  padding: 6px;
}
.panel img { display: block; width: 100%; image-rendering: pixelated; }
.phone {
  width: min(78%, 300px); margin: 0 auto;
  border: 4px solid var(--border); border-radius: 26px;
  box-shadow: 5px 6px 0 var(--shadow);
  overflow: hidden;
}
.phone img { display: block; width: 100%; }
.duo { display: flex; gap: 16px; justify-content: center; }
.duo .panel { flex: 1; max-width: 280px; }

/* ── Expedition plaques ── */
.plaque {
  font-family: var(--pixel); font-size: 10px; line-height: 1.9;
  letter-spacing: 0.5px; color: var(--ink-soft);
  border: 2px solid var(--border);
  background: var(--surface);
  box-shadow: 2px 3px 0 var(--shadow);
  padding: 12px 14px; margin-top: 18px; max-width: 46ch;
}

/* ── Postcards: a carousel. The centre card is biggest and in front; the rest sit
   behind it, fanned to the sides. Click any card and it rotates into the middle.
   JS sets each card's transform from its offset to the active card. ── */
.postcards {
  text-align: center;
  /* fixed 160px of air above — the field guide's caption needs the room */
  padding: 160px 0 clamp(48px, 8vw, 96px);
  overflow: hidden;                 /* clip the far, faded cards */
}
.postcards p { margin: 0 auto; }
.postcards .brief { color: var(--ink-soft); margin: 0 auto 8px; max-width: 52ch; }
/* joins the story sections' reveal */
.postcards { opacity: 0; transform: translateY(26px);
             transition: opacity 0.7s ease, transform 0.7s ease; }
.postcards.told { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .postcards { opacity: 1; transform: none; } }
.fan {
  position: relative; isolation: isolate; z-index: 0;
  height: clamp(250px, 42vw, 470px);
  margin-top: 24px;
}
.fan .card {
  position: absolute; left: 50%; top: 50%;
  width: clamp(150px, 22vw, 258px);
  margin: 0;
  border: 3px solid var(--border);
  box-shadow: 5px 7px 0 var(--shadow);
  image-rendering: pixelated;
  cursor: pointer;
  transition: transform 0.5s cubic-bezier(0.2, 0.85, 0.2, 1), opacity 0.4s ease, box-shadow 0.3s ease;
  will-change: transform;
}
.fan .card.center { cursor: default; box-shadow: 8px 11px 0 var(--shadow); }
@media (prefers-reduced-motion: reduce) { .fan .card { transition: none; } }

/* ── FAQ ── */
.faq { padding: clamp(48px, 8vw, 96px) 0; }
.faq h2 { text-align: center; margin-bottom: 36px; }
.faq details {
  background: var(--surface);
  border: 3px solid var(--border);
  box-shadow: 3px 4px 0 var(--shadow);
  margin-bottom: 14px; padding: 18px 20px;
}
.faq summary { font-weight: 800; cursor: pointer; }
/* Answers run the panel's width — the feature columns' 52ch cap has no business in
   here, where the panel itself is the measure. */
.faq details p { margin-top: 10px; max-width: none; }

/* ── Closing + footer ── */
.closing {
  text-align: center;
  padding: clamp(56px, 9vw, 110px) 20px;
  background: url("assets/world_collection.png") center / cover no-repeat;
  image-rendering: pixelated;
  border-top: 4px solid var(--border);
  position: relative;
}
.closing::after { content: ""; position: absolute; inset: 0; background: rgba(22,16,10,0.45); }
.closing > * { position: relative; z-index: 1; }
.closing h2 { color: #F0E3C2; text-shadow: 3px 3px 0 rgba(0,0,0,0.6); margin-bottom: 26px; }

footer {
  background: var(--border); color: #E8D9B5;
  padding: 28px clamp(16px, 4vw, 40px);
  display: flex; flex-wrap: wrap; gap: 18px;
  align-items: center; justify-content: space-between;
  font-size: 14px;
}
footer nav a { color: #E8D9B5; margin-right: 18px; }

/* ── Legal pages ── */
.legal {
  max-width: var(--panel); margin: 40px auto 80px;
  background: var(--surface);
  border: 3px solid var(--border);
  box-shadow: 5px 6px 0 var(--shadow);
  padding: clamp(24px, 5vw, 56px);
}
.legal h1 { font-family: var(--pixel); font-size: 18px; line-height: 1.7; margin-bottom: 6px; }
.legal .date { color: var(--ink-soft); font-size: 15px; margin-bottom: 30px; }
.legal h2 { font-family: var(--pixel); font-size: 12px; letter-spacing: 0.5px;
            margin: 34px 0 10px; color: var(--primary); }
.legal p, .legal li { color: var(--ink-soft); margin-bottom: 12px; }
.legal li { margin-left: 20px; }
.legal strong { color: var(--ink); }
.legal a { color: var(--primary); }
/* a button inside a legal panel keeps button ink — the link color painted
   SEE HOW IT WORKS orange-on-orange (invisible) on the About page */
.legal a.btn { color: #fff; }

/* About: the two of them, side by side above the story */
.about-pair { display: flex; justify-content: center; margin: 8px 0 26px; }
.about-pair img { width: min(78%, 340px); filter: drop-shadow(3px 4px 0 var(--shadow)); }
.faq .brief { text-align: center; margin: -24px auto 32px; color: var(--ink-soft); }

/* ── Field Dispatches: the blog, as a hand of wood-framed cards ──
   Same parchment panel + hard offset shadow as everything else; lifts on hover
   like the postcards do. Used both in the homepage preview and on the blog index. */
.dispatches { padding: 16px 0 clamp(48px, 8vw, 96px); text-align: center; }
.dispatches > .kicker { display: block; }
.dispatches h2 { text-align: center; margin: 12px 0 8px; }
.dispatches .brief { color: var(--ink-soft); margin: 0 auto 8px; max-width: 52ch; }
.dispatch-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: clamp(16px, 2.4vw, 24px);
  margin-top: 40px; text-align: left;
}
@media (max-width: 760px) { .dispatch-grid { grid-template-columns: 1fr; } }
.dispatch {
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 3px solid var(--border);
  box-shadow: 4px 5px 0 var(--shadow);
  padding: 22px 20px; text-decoration: none; color: inherit;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.dispatch:hover { transform: translate(-2px, -3px); box-shadow: 6px 9px 0 var(--shadow); }
.dispatch .kicker { font-size: 10px; }
.dispatch h3 {
  font-family: var(--round); font-weight: 800; font-size: 19px; line-height: 1.3;
  color: var(--ink); margin: 10px 0;
}
.dispatch p { color: var(--ink-soft); font-size: 15px; max-width: none; margin: 0 0 16px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.dispatch .more {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--pixel); font-size: 10px; color: var(--primary); margin-top: auto;
}
.more-arrow { display: block; }
.dispatch .tag { display: inline-flex; align-items: center; gap: 6px; }

/* The blog index reuses the grid but stands on the parchment page, not inside a panel. */
.dispatch-page { max-width: var(--page); margin: 0 auto; padding: clamp(40px, 7vw, 72px) clamp(16px, 4vw, 40px) 80px; }
.dispatch-page .kicker { text-align: center; display: block; }
.dispatch-page .act { display: block; width: fit-content; margin: 0 auto 14px; }
.dispatch-page h1 { font-family: var(--pixel); font-size: clamp(16px, 2.4vw, 22px); line-height: 1.7; text-align: center; margin: 12px 0 8px; }
.dispatch-page .brief { text-align: center; color: var(--ink-soft); margin: 0 auto 8px; max-width: 56ch; }
.dispatch-page .dispatch-grid { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
/* A featured lead card spanning the row, for the flagship comparison piece. */
/* the lead folder sits in the grid like everyone else — its tag does the talking */
.dispatch .tag { font-family: var(--pixel); font-size: 9px; color: var(--primary); letter-spacing: 1px; }

/* Blog articles get a wider panel than the legal pages — room for tables and
   screenshots — while privacy/terms keep the narrow 720px reading measure. */
.legal.article { max-width: var(--panel); }
/* Center the warning-sign call-outs within an article (box and its text). */
.legal.article .plaque { margin-left: auto; margin-right: auto; text-align: center; }

/* ── Article footer nav: quiet. An arrow and a title either side of the one
   button — no boxes, no tabs. The folders live on the index; down here you
   just need the way out. */
.article-nav {
  max-width: var(--panel);
  margin: 34px auto 72px;
  display: grid; grid-template-columns: 1fr auto 1fr; gap: 18px;
  align-items: center;
}
/* Fixed-shape controls: both boxes fill their grid column at one height, and
   a long title truncates with an ellipsis — never a second line, never a
   different-sized control. */
.an-prev, .an-next {
  display: flex; align-items: center; gap: 10px;
  min-width: 0;
  padding: 13px 16px;
  background: var(--surface);
  border: 3px solid var(--border);
  box-shadow: 3px 4px 0 var(--shadow);
  font-weight: 800; font-size: 15px; line-height: 1.2;
  color: var(--ink); text-decoration: none;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.an-prev:hover, .an-next:hover { transform: translate(-2px, -3px); box-shadow: 5px 7px 0 var(--shadow); }
.an-prev span, .an-next span {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.an-next { justify-content: flex-end; }
.an-prev img { transform: scaleX(-1); }
.an-prev img, .an-next img { flex-shrink: 0; }
.an-all { justify-self: center; }
@media (max-width: 760px) {
  .article-nav { grid-template-columns: 1fr; }
  .an-all { justify-self: center; order: 3; }
}

/* ── Comparison table (the "best habit tracking apps" piece) ── */
.compare-wrap { overflow-x: auto; margin: 28px 0; border: 3px solid var(--border); box-shadow: 4px 5px 0 var(--shadow); }
table.compare { border-collapse: collapse; width: 100%; min-width: 560px; background: var(--surface); font-size: 15px; }
table.compare th, table.compare td { border: 1px solid var(--border); padding: 12px 14px; text-align: left; color: var(--ink-soft); vertical-align: top; }
table.compare thead th { font-family: var(--pixel); font-size: 10px; line-height: 1.6; color: #fff; background: var(--primary); }
table.compare tbody th { font-weight: 800; color: var(--ink); background: rgba(210,166,63,0.16); white-space: nowrap; }
table.compare td.us { background: rgba(79,107,65,0.16); color: var(--ink); font-weight: 700; }
table.compare tbody tr:nth-child(even) td { background: rgba(74,46,23,0.04); }
table.compare tbody tr:nth-child(even) td.us { background: rgba(79,107,65,0.20); }


/* ── Hero: floating gems + a bobbing wordmark over the temple entrance ── */
.hero .gems { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.hero .gem {
  position: absolute; width: clamp(40px, 5vw, 64px);
  /* smooth: these sprites are anti-aliased 256px art, not hard-grid pixels */
  filter: drop-shadow(2px 3px 0 rgba(0,0,0,0.5));
  opacity: 0.92;
  animation: gem-float 7s ease-in-out infinite;
}
.hero .gem.g1 { left: 7%;  top: 24%; animation-duration: 6.5s; }
.hero .gem.g2 { right: 9%;  top: 30%; animation-duration: 7.6s; animation-delay: -1.2s; }
.hero .gem.g3 { left: 13%; bottom: 18%; animation-duration: 8.2s; animation-delay: -2.4s; }
.hero .gem.g4 { right: 14%; bottom: 24%; animation-duration: 6.9s; animation-delay: -0.6s; }
.hero .gem.g5 { left: 47%; top: 9%; width: clamp(28px, 3.6vw, 46px); animation-duration: 9s; animation-delay: -3.3s; }
@keyframes gem-float {
  0%, 100% { transform: translateY(0) rotate(-7deg); }
  50%      { transform: translateY(-22px) rotate(7deg); }
}
.hero img.mark { animation: logo-bob 4.5s ease-in-out infinite; }
@keyframes logo-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-12px); }
}
@media (prefers-reduced-motion: reduce) {
  .hero .gem, .hero img.mark { animation: none; }
}


/* ── Field-notes cards as file folders: the category rides a tab up top ──
   The tab is inset from the left edge (like a real folder), carries its own
   left/top/right borders, and overlaps the card's top border by exactly the
   border width — same surface fill, so tab and body read as one folder. No
   cover strips: the card keeps its full border on all four sides. */
/* One sheet folded in two. The card's ground is the BACK half (darker manila,
   the tab is cut from it). Papers peek out of the fold. The FRONT half overlaps
   from ~34px down with its own visible top edge — the parchment face the text
   sits on. Everything inside the one whole border = the folder's silhouette. */
.dispatch {
  position: relative; margin-top: 30px;
  background: color-mix(in srgb, var(--surface) 74%, #8A6A3F);
  padding-top: 56px;
}
/* papers in the fold */
.dispatch::before {
  content: ""; position: absolute; top: 12px; left: 20px; right: 34px;
  height: 28px; z-index: 0;
  background: #FCF7E6;
  border: 3px solid var(--border); border-bottom: 0;
  transition: transform 0.1s ease;
}
.dispatch:hover::before { transform: translateY(-8px); }
/* the front half, folded up over the papers — cut slightly PROUD of the back,
   with its own edge and thrown shadow, so the two halves read as two planes */
.dispatch::after {
  content: ""; position: absolute; left: -6px; right: -6px; bottom: -6px; top: 34px;
  z-index: 0;
  background: var(--surface);
  border: 3px solid var(--border);
  box-shadow: 4px 5px 0 var(--shadow);
}
.dispatch > * { position: relative; z-index: 1; }
.dispatch .kicker {
  position: absolute; left: 14px; top: -25px; margin: 0; z-index: 1;
  background: color-mix(in srgb, var(--surface) 74%, #8A6A3F);
  border: 3px solid var(--border);
  border-bottom: 0;
  /* the tab's side borders end exactly where they meet the folder's top line:
     3 (border) + 6 + 10 (line) + 6 = 25 = the offset. No dipping past the fold. */
  padding: 6px 16px; line-height: 1;
  font-size: 10px; color: var(--primary);
}
/* lead (comparison) card: its ★ tag tucks beside the title */
.dispatch.lead .tag { display: inline-block; margin-bottom: 4px; }

/* ── Opening a field-notes folder: the article panel wears the same tab as its
   card, with a hint of stacked pages behind — so a page reads as an open folder.
   Same construction as the cards: tab inset from the left, own borders, overlaps
   the panel's top border by the border width. The panel border stays whole. */
.legal.article {
  position: relative; margin-top: 52px;
  /* the OPENED folder: manila ground (same stock as the card backs), a rim of
     it showing all around the paper sheet the article is printed on */
  background: color-mix(in srgb, var(--surface) 74%, #8A6A3F);
  box-shadow: 5px 6px 0 var(--shadow), 11px 14px 0 rgba(66, 45, 26, 0.16);
  padding: 72px clamp(38px, 6vw, 76px) 52px;
}
.legal.article::after {
  content: ""; position: absolute; inset: 46px 20px 20px; z-index: 0;
  background: #FCF7E6;
  border: 3px solid var(--border);
  box-shadow: 3px 4px 0 rgba(66, 45, 26, 0.28);
}
.legal.article > * { position: relative; z-index: 1; }
/* Opening the folder: the page slides up out of it — paper layer and the ink
   on it move as one sheet. The folder itself stays put. */
@keyframes paper-rise {
  from { opacity: 0; transform: translateY(30px); }
  to   { opacity: 1; transform: translateY(0); }
}
.legal.article::after { animation: paper-rise 0.55s cubic-bezier(0.2, 0.85, 0.2, 1) 0.12s both; }
.legal.article > * { animation: paper-rise 0.55s cubic-bezier(0.2, 0.85, 0.2, 1) 0.12s both; }
@media (prefers-reduced-motion: reduce) {
  .legal.article::after, .legal.article > * { animation: none; }
}
.legal.article::before {
  content: "FIELD DISPATCH";
  position: absolute; left: 18px; top: -28px; z-index: 1;
  background: color-mix(in srgb, var(--surface) 74%, #8A6A3F);
  border: 3px solid var(--border); border-bottom: 0;
  /* 3 + 7 + 11 + 7 = 28 = the offset — side borders stop at the panel line */
  padding: 7px 20px; line-height: 1;
  font-family: var(--pixel); font-size: 11px; letter-spacing: 1px;
  color: var(--primary);
}

/* ═══ STORY HOMEPAGE (feature/story-homepage exploration) ═══
   The page as an expedition told in acts, ending in a field-guide carousel. */

.hero.story h1 { line-height: 2; }
.scroll-hint {
  margin-top: 34px; font-family: var(--pixel); font-size: 9px; letter-spacing: 2px;
  color: rgba(240, 227, 194, 0.65); animation: hint-bob 2.2s ease-in-out infinite;
}
@keyframes hint-bob { 0%,100% { transform: translateY(0);} 50% { transform: translateY(6px);} }


.chapter {
  padding: clamp(52px, 9vw, 110px) 0 0;
  text-align: center;
  opacity: 0; transform: translateY(26px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}
.chapter.told, .fieldguide.told { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .chapter, .fieldguide { opacity: 1; transform: none; } }
.act {
  /* Gold on raw tan measured 1.15:1 — invisible. On the wood-brown chip it's 5.47:1. */
  display: inline-block;
  font-family: var(--pixel); font-size: 10px; letter-spacing: 3px;
  color: var(--gold); background: var(--border);
  padding: 7px 14px 8px; margin-bottom: 14px;
  box-shadow: 2px 3px 0 var(--shadow);
  text-transform: uppercase;
}
.chapter h2 { margin: 0 0 18px; }
.chapter p { margin: 0 auto 14px; max-width: var(--prose); }
.chapter .plaque { margin: 22px auto 0; text-align: center; }

/* A wide slice of world art between beats — the scenery rolling past the caravan. */
.sceneband {
  height: clamp(150px, 24vw, 260px); margin-top: 34px;
  background: var(--scene) var(--pos, center) / cover no-repeat;
  image-rendering: pixelated;
  border: 3px solid var(--border);
  box-shadow: 5px 6px 0 var(--shadow);
}
.couponframe { max-width: 420px; margin: 30px auto 0; }
.couponframe img {
  width: 100%; image-rendering: pixelated;
  border: 3px solid var(--border); box-shadow: 5px 6px 0 var(--shadow);
  transform: rotate(-2deg);
}

/* ── The field guide: a phone-screens carousel with a narrated caption ── */
.fieldguide {
  padding: clamp(64px, 10vw, 120px) 0 0;
  text-align: center;
  opacity: 0; transform: translateY(26px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}
.guide-brief { color: var(--ink-soft); margin: 0 auto; }
.guide { position: relative; isolation: isolate; z-index: 0; height: clamp(360px, 58vw, 560px); margin-top: 26px; overflow-x: clip; }
.guide-stage { position: absolute; inset: 0; }
.shot {
  position: absolute; left: 50%; top: 50%;
  width: clamp(170px, 26vw, 250px); margin: 0;
  cursor: pointer;
  transition: transform 0.45s cubic-bezier(0.2, 0.85, 0.2, 1), opacity 0.35s ease;
  will-change: transform;
}
.shot img {
  display: block; width: 100%;
  border: 4px solid var(--border); border-radius: 22px;
  box-shadow: 5px 6px 0 var(--shadow);
}
.shot.center { cursor: default; }
.shot.center img { box-shadow: 8px 10px 0 var(--shadow); }
.guide-arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 20;
  /* our own pixel triangle (the play icon), not a font glyph — glyph baselines
     never sat centered */
  width: 48px; height: 48px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--primary);
  border: 3px solid var(--border); box-shadow: 3px 4px 0 var(--shadow);
  cursor: pointer;
}
.guide-arrow img { display: block; width: 22px; height: 22px; }
.guide-arrow.prev img { transform: scaleX(-1); }
.guide-arrow { transition: transform 0.1s ease, box-shadow 0.1s ease, filter 0.1s ease; }
.guide-arrow:hover { transform: translate(-2px, calc(-50% - 3px)); box-shadow: 5px 7px 0 var(--shadow); filter: brightness(1.1); }
.guide-arrow:active { transform: translateY(calc(-50% + 3px)); box-shadow: 1px 1px 0 var(--shadow); filter: none; }
.guide-arrow.prev { left: max(6px, 3vw); }
.guide-arrow.next { right: max(6px, 3vw); }
.guide-caption { max-width: 560px; margin: 18px auto 0; padding: 18px 26px; }
.guide-caption h3 { font-family: var(--pixel); font-size: 13px; margin-bottom: 8px; color: var(--ink); }
.guide-caption p { color: var(--ink-soft); font-size: 15px; margin: 0 auto; }
.guide-dots { display: flex; gap: 10px; justify-content: center; margin-top: 14px; }
.dot {
  width: 12px; height: 12px; padding: 0; cursor: pointer;
  background: var(--bg); border: 2px solid var(--border);
}
.dot.on { background: var(--primary); }

.closing-sub {
  color: #F0E3C2; opacity: 0.92; margin: 0 auto 24px; max-width: 46ch;
  text-shadow: 1px 2px 0 rgba(0,0,0,0.5);
}

/* Cascade fix: the .fieldguide base rule above re-hid the section for
   reduced-motion users (later rule, same specificity). Re-state the exception
   LAST so it always wins — nobody gets an invisible page. */
@media (prefers-reduced-motion: reduce) {
  .chapter, .fieldguide { opacity: 1; transform: none; }
}

/* The closing lives in a <div>, so `section h2` never reached it — pin the display face. */
.closing h2 { font-family: var(--pixel); font-size: clamp(15px, 2.2vw, 20px); line-height: 1.7; }

/* ═══ PHASE 2 · THE BRIEFING — a panorama, not slides ═══
   The camera dollies into each scene; a scene leaves by PARTING down the middle
   (the entrance-doors motif) revealing the next place — or the dark of the mine.
   A subtitle band types the story like game dialogue. */
#cutscene {
  position: fixed; inset: 0; z-index: 90;
  display: none;
  background: #0b0805;           /* the dark the doors part onto */
  cursor: pointer;
  overflow: hidden;
}
#cutscene.open { display: block; }
#cutscene.done { animation: cs-out 0.65s ease forwards; }
@keyframes cs-out { to { opacity: 0; visibility: hidden; } }
.cs-stage { position: absolute; inset: 0; }

/* ── Scenes: full-bleed places, split in two halves so they can part ── */
.cs-scene { position: absolute; inset: 0; opacity: 0; }
.cs-scene.on { opacity: 1; animation: cs-dolly 10s ease-out forwards; }
.cs-scene.sSunset.on { animation: cs-dolly-deep 12s linear forwards; }
.cs-scene.exit-fade, .cs-scene.exit, .cs-scene.exit-cut { animation-play-state: paused; }
/* the door reveal: a HARD cut under the slam — no dissolve, the open doors
   are simply there when the shake hits */
.cs-scene.exit-cut { opacity: 0; transition: none; }
@keyframes cs-dolly { from { transform: scale(1); } to { transform: scale(1.17); } }
@keyframes cs-dolly-deep { from { transform: scale(1); } to { transform: scale(1.34); } }
.cs-scene .half {
  position: absolute; top: 0; bottom: 0; width: 50.6%;
  overflow: hidden;
  transition: transform 1.1s cubic-bezier(0.5, 0, 0.8, 0.4);
}
.cs-scene .half.l { left: 0; }
.cs-scene .half.r { right: 0; }
.cs-scene .half img {
  position: absolute; top: 0; height: 100%; width: 198%; max-width: none;
  object-fit: cover; image-rendering: pixelated;
}
.cs-scene .half.l img { left: 0; }
.cs-scene .half.r img { right: 0; }
/* The trail render is square; the 16:9 cover crop keeps the middle and beheads
   the travellers at the bottom. Anchor its window low so they stay in frame. */
.cs-scene.s1 .half img { object-position: center center; } /* native 16:9 stage */
.cs-scene.sGrotto .half img { object-position: center center; } /* native 16:9 */
.cs-scene.exit .half.l, .cs-scene.exit .half.r { transform: none; }
.cs-scene.exit { opacity: 0; transition: opacity 0.9s ease; }
.cs-scene.exit { z-index: 10; }     /* the parting scene slides OVER the next one */
.cs-scene.on:not(.exit) { z-index: 5; }
/* a gentle dark grade so subtitles always read */
.cs-scene::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(rgba(11,8,5,0.12), rgba(11,8,5,0.42)); }

/* ── The dark of the mine (beat 3): torchlight on black ── */
.cs-torch {
  position: absolute; inset: 0; opacity: 0; transition: opacity 0.9s ease; z-index: 4;
  background:
    radial-gradient(42% 34% at 32% 48%, rgba(255, 170, 60, 0.30), transparent 70%),
    radial-gradient(38% 30% at 68% 44%, rgba(255, 150, 40, 0.26), transparent 70%);
  mix-blend-mode: screen;
  animation: flicker 0.42s steps(2) infinite;
}
#cutscene.b3 .cs-torch, #cutscene.b4 .cs-torch { opacity: 1; }

/* ── b1: the geared travellers WALK the trail — PixelLab cycles, 128px frames ── */
.cs-walker {
  position: absolute; left: 0; bottom: 12%;
  width: 128px; height: 128px; z-index: 20;
  filter: drop-shadow(3px 4px 0 rgba(0,0,0,0.5));
  opacity: 0;
}
.cs-walker.w-dog  { background: url("assets/walk_dog_strip.png")  0 0 / 1024px 128px no-repeat; }
.cs-walker.w-pika { width: 164px; height: 164px; background: url("assets/walk_pika_strip.png") 0 0 / 1312px 164px no-repeat; animation-name: cs-swing8, cs-cross-b !important; }
#cutscene.b1 .cs-walker.w-dog {
  opacity: 1;
  animation: cs-frames8 0.9s steps(8) infinite, cs-cross 5.2s linear forwards;
}
#cutscene.b1 .cs-walker.w-pika {
  opacity: 1; margin-left: -70px;
  animation: cs-frames8 0.9s steps(8) infinite, cs-cross-b 5.2s linear forwards;
}
@keyframes cs-frames8 { to { background-position: -1024px 0; } }
@keyframes cs-cross {
  /* Start clear of the corner ferns and GROW with the camera: the dolly pushes
     in, so the foreground pair swells with it — one zoom, not a slide-past. */
  /* the dirt runs ~25vw-75vw; the fern banks own both corners — the whole
     journey stays on the path, never on the plants */
  from { transform: translate(27vw, 0) scale(1.0); }
  to   { transform: translate(58vw, -1vh) scale(1.18); }
}
@keyframes cs-cross-b {   /* same journey, half a step behind — never snaps */
  /* the pika's frames are 164px to the dog's 128 — scaled to the same shoulder
     height (164 x 0.78 = 128), growing with the dolly exactly like the dog */
  from { transform: translate(23.5vw, 0.5vh) scale(0.78); }
  to   { transform: translate(50.5vw, -2vh) scale(0.92); }
}

/* ── b2/b3: standing before the entrance, proportional to it ── */
.cs-stander {
  position: absolute; bottom: 11%;
  height: clamp(64px, 11vh, 104px); z-index: 20;
  filter: drop-shadow(3px 4px 0 rgba(0,0,0,0.5));
  opacity: 0; transition: opacity 0.6s ease;
  --flip: 1;
  transform: scaleX(var(--flip));
  transform-origin: 50% 100%;
}
.st-dog  { left: 35%; --flip: -1; --dx: -2.1vw; }   /* faces the door, like the pika */
.st-pika { left: 59%; --dx: 2vw; }
/* ANCHORED to the ground they stand on: the scene dollies (scale 1->1.17 about
   the viewport centre, 10s ease-out), so each stander rides the same zoom —
   translated outward from that centre by their own offset, growing in step.
   ONE continuous ride across b2 AND b3: nothing restarts at the door reveal
   (the incoming sOpen scene joins the same clock via a negative delay set
   in show()), so the pair holds its exact spot through the slam. */
@keyframes cs-stand-dolly {
  from { transform: translate(0, 0) scale(1) scaleX(var(--flip)); }
  to   { transform: translate(var(--dx), 6.6vh) scale(1.17) scaleX(var(--flip)); }
}
#cutscene.b2 .cs-stander, #cutscene.b3 .cs-stander {
  opacity: 1;
  animation: cs-stand-dolly 10s ease-out forwards;
}

/* The doors SLAM: the whole stage jolts as b3 lands (steps() keeps it pixel-y). */
@keyframes cs-slam {
  0%, 100% { transform: translate(0, 0); }
  15% { transform: translate(-8px, 5px); }
  35% { transform: translate(7px, -4px); }
  55% { transform: translate(-5px, 3px); }
  75% { transform: translate(3px, -2px); }
}
#cutscene.slam .cs-stage { animation: cs-slam 0.5s steps(2, end) 1; }

/* b3 finale: a fast accelerating push INTO the open doorway (origin on the
   dark opening), the pair sweeping out of frame with the same dive — then the
   beat cuts to the grotto right as it lands. `from` matches the dolly's
   typical mid-flight state so the dive picks up where the push-in was. */
#cutscene.b3.zoomdoor .cs-scene.sOpen.on {
  transform-origin: 50% 55%;
  animation: cs-door-zoom 0.95s cubic-bezier(0.55, 0, 0.85, 0.36) forwards;
}
@keyframes cs-door-zoom {
  from { transform: scale(1.13); }
  to   { transform: scale(2.7); }
}
/* During the dive the pair stays glued to the ground it stands on: the same
   zoom factor as the scene (1.13 -> 2.7 about the viewport centre), the same
   curve, so they leave frame gradually WITH the floor — no fade, no flash.
   from matches the live dolly state at zoom start to within a couple px. */
#cutscene.b3.zoomdoor .cs-stander {
  animation: cs-stand-zoom 0.95s cubic-bezier(0.55, 0, 0.85, 0.36) forwards;
}
@keyframes cs-stand-zoom {
  from { transform: translate(calc(var(--dx) * 0.76), 5vh) scale(1.13) scaleX(var(--flip)); }
  to   { transform: translate(calc(var(--dx) * 10), 66vh) scale(2.7) scaleX(var(--flip)); }
}
@media (prefers-reduced-motion: reduce) { #cutscene.slam .cs-stage { animation: none; } }

/* ── b4: inside the grotto — the game's own room and animations ── */
.cs-boulder {
  position: absolute; z-index: 19; image-rendering: pixelated; opacity: 0;
  transition: opacity 0.5s ease 0.3s;
}
.bl-l { left: 33%; bottom: 12%; width: 170px; --dx: -1.9vw; }
.bl-r { right: 31%; bottom: 12%; width: 102px; --dx: 2.6vw; }
.cs-boulder { transform-origin: 50% 100%; }
#cutscene.b4 .cs-boulder { opacity: 1; animation: cs-ride 10s ease-out forwards; }

/* ANCHORED to the grotto floor: everyone in the mine rides the scene's own
   dolly (outward from the viewport centre, growing in step) — same fix as the
   temple standers, so nothing shifts against the ground during the push-in. */
@keyframes cs-ride {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(var(--dx), 6.5vh) scale(1.17); }
}
/* the dog: rigged 160px web mining cycle (the game's 64px frames fall apart
   blown up to web scale — same character, rendered for this stage) */
.cs-dig {
  position: absolute; left: 41%; bottom: 12%;
  width: 160px; height: 160px; z-index: 20;
  background: url("assets/dig_dog_web_strip.png") 0 0 / 1280px 160px no-repeat;
  filter: drop-shadow(3px 4px 0 rgba(0,0,0,0.6));
  opacity: 0;
  --dx: -0.7vw; transform-origin: 50% 100%;
}
#cutscene.b4 .cs-dig { opacity: 1; animation: cs-dig-run 0.9s steps(8) infinite, cs-ride 10s ease-out forwards; }
@keyframes cs-dig-run { to { background-position: -1280px 0; } }
/* the pika: PixelLab swing cycle, hardhat + pickaxe */
.cs-swing {
  position: absolute; right: 38%; bottom: 12%;
  width: 164px; height: 164px; z-index: 20;
  background: url("assets/swing_pika_strip.png") 0 0 / 1312px 164px no-repeat;
  filter: drop-shadow(3px 4px 0 rgba(0,0,0,0.6));
  opacity: 0;
  --dx: 1.1vw; transform-origin: 50% 100%;
}
#cutscene.b4 .cs-swing { opacity: 1; animation: cs-swing8 0.9s steps(8) infinite, cs-ride 10s ease-out forwards; }
@keyframes cs-swing8 { to { background-position: -1312px 0; } }
/* Gems come FROM the rock, like the game: the boulders step intact ->
   cracked -> crumbling under the pickaxes (src swaps timed in show()), and a
   gem appears at each broken boulder near the end — riding the dolly so it
   sits ON the rock it came out of. cg3 stays retired. */
.cs-gem { display: none; position: absolute; width: 42px; z-index: 21;
          filter: drop-shadow(2px 3px 0 rgba(0,0,0,0.55)); }
.cs-gem.cg1 { left: 35.5%; bottom: 23%; --dx: -1.9vw; --pop: 5.2s; }
.cs-gem.cg2 { right: 32.5%; bottom: 21%; --dx: 2.5vw; --pop: 6s; }
.cs-gem.cg3 { display: none !important; }
#cutscene.b4 .cs-gem.cg1, #cutscene.b4 .cs-gem.cg2 {
  display: block; transform-origin: 50% 100%;
  animation: cs-gem-in 0.5s ease var(--pop) both, cs-ride 10s ease-out forwards;
}
@keyframes cs-gem-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes cs-pop { from { opacity: 0; transform: scale(0.3) translateY(16px); }
                    to { opacity: 1; transform: scale(1) translateY(0); } }

/* b2: the checklist IS the product — the app's parchment habit rows, centered
   and unmistakable, ticking with our own pixel check. */
.cs-list {
  position: absolute; left: 0; right: 0; top: 12%; margin: 0 auto;
  width: min(430px, 84vw); z-index: 22;
  display: grid; gap: 10px; text-align: left;
  opacity: 0; transform: translateY(-12px);
  transition: opacity 0.6s ease 0.8s, transform 0.6s ease 0.8s;
}
#cutscene.b2 .cs-list { opacity: 1; transform: none; }
/* the nameplate: parchment, so it reads against any temple (wood-on-brown sank) */
.cs-list-title {
  justify-self: center;
  font-family: var(--pixel); font-size: 12px; letter-spacing: 1.5px;
  color: var(--primary); background: var(--surface);
  border: 3px solid var(--border);
  box-shadow: 3px 4px 0 rgba(0, 0, 0, 0.45);
  padding: 10px 20px 11px; margin-bottom: 4px;
}
/* HomeRow, verbatim from the carmen-cv demo (which ported it from the app):
   54px well grid / 30px trailing slot / 16px padding, brass inner rule inset 5,
   rowDone = sage@14% flat + settle into the shadow, knock 1.035, the mark
   stamps at 1.35 with a -12deg twist, +pts fly up and fade. Ticks run on their
   own AND on click. */
.cs-habit {
  position: relative;
  display: grid; grid-template-columns: 54px minmax(0, 1fr) 30px;
  align-items: center; gap: 16px;
  width: 100%; text-align: left; padding: 16px;
  background: var(--surface);
  border: 3px solid var(--border);
  box-shadow: 3px 4px 0 0 rgba(66, 45, 26, 0.85);
  cursor: pointer;
  font-family: var(--round);
  /* springy pop up, then a soft settle into the shadow — two beats, not one */
  transition: transform 260ms cubic-bezier(0.2, 1.5, 0.4, 1),
    background-color 320ms ease, box-shadow 260ms ease;
}
.cs-habit::after {
  content: ""; position: absolute; inset: 5px;
  border: 1px solid rgba(210, 166, 63, 0.55);
  pointer-events: none;
}
.cs-habit.done {
  background: color-mix(in srgb, var(--sage) 14%, var(--surface));
  box-shadow: none; transform: translate(3px, 4px);
}
.cs-habit.knock { transform: scale(1.06); }
.cs-habit.done.knock { transform: translate(3px, 4px) scale(1.06); }
.cs-habit .well {
  width: 54px; height: 54px;
  display: grid; place-items: center;
  background: rgba(210, 166, 63, 0.16);   /* wellIdle */
  border: 3px solid var(--border);
}
.cs-habit.done .well { background: rgba(79, 107, 65, 0.22); }  /* wellDone */
.cs-habit .well img { width: 30px; height: 30px; }
.cs-habit .hbody { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cs-habit .hname {
  font-size: 16px; font-weight: 700; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cs-habit.done .hname { color: var(--ink-soft); text-decoration: line-through; }
.cs-habit .hpts { font-size: 13px; font-weight: 800; color: var(--primary); }
.cs-habit.done .hpts { color: var(--sage); }
.cs-habit .tick { position: relative; width: 30px; height: 30px; }
.cs-habit .tick img { position: absolute; inset: 0; width: 30px; height: 30px; }
.cs-habit .tick .c { opacity: 0.6; transform: scale(0.9);
  transition: opacity 200ms ease; }
.cs-habit .tick .k { opacity: 0; transform: scale(0.9);
  transition: transform 220ms cubic-bezier(0.2, 1.6, 0.4, 1), opacity 200ms ease; }
.cs-habit.done .tick .c { opacity: 0; }
.cs-habit.done .tick .k { opacity: 1; transform: scale(1); }
.cs-habit.done.knock .tick .k { transform: scale(1.35) rotate(-12deg); }
.hfly {
  position: absolute; right: 46px; top: 50%;
  font-family: var(--pixel); font-size: 10px; color: var(--primary);
  pointer-events: none;
  animation: hfly 700ms ease-out forwards;
}
@keyframes hfly { from { transform: translateY(0); opacity: 1; }
                  to { transform: translateY(-34px); opacity: 0; } }

/* b4: the ticket itself rises in the vault — the plain coupon UI, scalloped
   edge and all, no postcard frame (Carmen: the wood-and-logo card was a lot). */
.cs-coupon {
  position: absolute; left: 50%; top: 42%; z-index: 22;
  width: clamp(280px, 36vw, 460px);
  filter: drop-shadow(6px 8px 0 rgba(0,0,0,0.5));
  opacity: 0; transform: translate(-50%, -40%) rotate(-2.5deg) scale(0.92);
  /* fast OUT (so it never lingers into the finale), slow IN on its own beat */
  transition: opacity 0.22s ease, transform 0.22s ease;
}
#cutscene.b5 .cs-coupon {
  opacity: 1; transform: translate(-50%, -50%) rotate(-2.5deg) scale(1);
  transition: opacity 0.7s ease 0.9s, transform 0.7s cubic-bezier(0.2, 0.85, 0.2, 1) 0.9s;
}

/* b5: the finale lockup — headline over the button, centered high on the stage */
.cs-finale {
  position: absolute; left: 0; right: 0; top: 26%;
  display: grid; justify-items: center; gap: 26px; z-index: 25;
  opacity: 0; transition: opacity 0.7s ease 0.9s;
  pointer-events: none;
}
#cutscene.b6 .cs-finale { opacity: 1; pointer-events: auto; }
.cs-finale-line {
  font-family: var(--pixel); font-size: clamp(15px, 2.4vw, 24px); line-height: 2;
  color: #F0E3C2; text-shadow: 3px 3px 0 rgba(0,0,0,0.7); text-align: center;
}
.cs-begin { font-size: 12px; padding: 15px 28px; cursor: pointer; }
#cutscene.b6 .cs-caption { display: none; }

/* ── b6: walking out toward the sunset, seen from behind ── */
.cs-backwalker {
  position: absolute; left: 50%; bottom: 14%;
  width: 128px; height: 128px; z-index: 20;
  filter: drop-shadow(3px 4px 0 rgba(0,0,0,0.5));
  opacity: 0;
}
/* Side-by-side INTO the distance: the offset lives AFTER scale in the
   transform, so the gap between them shrinks with their bodies — a fixed
   pixel gap read as them drifting apart as they shrank (Carmen). ±70px at
   scale 1 = a sliver of air at full size, the same sliver at the horizon. */
.cs-backwalker { margin-left: -64px; --sx: 0px; }
.bw-dog  { --sx: -70px; background: url("assets/walkback_dog_strip.png")  0 0 / 1024px 128px no-repeat; }
.bw-pika { --sx: 70px;  background: url("assets/walkback_pika_strip.png") 0 0 / 1024px 128px no-repeat; }
#cutscene.b6 .cs-backwalker {
  opacity: 1;
  animation: cs-frames8 1s steps(8) infinite, cs-away 11s linear forwards;
}
@keyframes cs-away {
  0%   { transform: translateY(8vh) scale(1.9) translateX(var(--sx)); opacity: 1; }
  78%  { opacity: 1; }
  100% { transform: translateY(-24vh) scale(0.28) translateX(var(--sx)); opacity: 0; }  /* they disappear into the light */
}

/* ── Subtitle band ── */
.cs-caption {
  /* ONE fixed dialogue plate for every line — same place, same size, same box,
     every beat (Carmen: floating subtitles got lost against changing scenery).
     Centered without transforms so the pixel font stays on whole pixels; a
     two-line min-height so the plate never jumps as text types. */
  position: absolute; left: 0; right: 0; bottom: 28px;
  margin: 0 auto; z-index: 45;
  width: min(720px, 90vw); min-height: 74px;
  padding: 16px 22px; text-align: left;
  background: rgba(6, 4, 3, 0.82);
  border: 3px solid var(--border);
  font-family: var(--pixel); font-size: 13px; line-height: 2;
  color: #F0E3C2;
}
@media (max-width: 760px) { .cs-caption { font-size: 11px; min-height: 64px; } }
.cs-caret { visibility: hidden; display: inline-block; margin-left: 10px;
            animation: cs-caret-blink 0.9s steps(1) infinite; }
/* our pixel triangle, rotated to point down, riding the text's optical middle */
.cs-caret img { display: inline-block; transform: rotate(90deg); vertical-align: 1px; }
.cs-caret.shown { visibility: visible; }
@keyframes cs-caret-blink { 50% { opacity: 0; } }

.cs-skip {
  position: absolute; top: 18px; right: 20px; z-index: 46;
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--pixel); font-size: 9px; letter-spacing: 1px;
  color: rgba(240, 227, 194, 0.75);
  /* a quiet plate from the caption's family — the button reads the same on
     every scene, midday sky included, instead of washing out */
  background: rgba(22, 16, 10, 0.55);
  border: 2px solid rgba(240, 227, 194, 0.18);
  cursor: pointer;
  padding: 9px 12px;
}
.cs-skip img { display: block; opacity: 0.75; }
.cs-skip img:first-of-type { margin-left: 3px; }
.cs-skip:hover { color: #F0E3C2; }
.cs-skip:hover img { opacity: 1; }

/* the music toggle: same plate family as SKIP, parked top-left */
.cs-mute {
  position: absolute; top: 18px; left: 20px; z-index: 46;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(22, 16, 10, 0.55);
  border: 2px solid rgba(240, 227, 194, 0.18);
  cursor: pointer;
  padding: 8px 10px;
}
.cs-mute img { display: block; opacity: 0.85; }
.cs-mute:hover img { opacity: 1; }

/* PHASE 3 tweaks: compact hero + replay link + field-notes reveal */
.hero.compact { min-height: 64vh; }
.replay { margin-top: 24px; }
.replay a {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--pixel); font-size: 9px; letter-spacing: 1px;
  color: rgba(240, 227, 194, 0.75); text-decoration: none;
}
.replay a:hover { color: #F0E3C2; text-decoration: underline; }
.replay-play { display: block; width: 14px; height: 14px; }
.replay-copy { transform: translateY(2px); }
.dispatches { opacity: 0; transform: translateY(26px);
              transition: opacity 0.7s ease, transform 0.7s ease; }
.dispatches.told { opacity: 1; transform: none; }

/* Reduced motion: no cutscene, everything at rest. LAST so it always wins. */
@media (prefers-reduced-motion: reduce) {
  #cutscene { display: none !important; }
  .chapter, .fieldguide, .dispatches { opacity: 1; transform: none; }
  .cs-dig, .cs-torch { animation: none; }
}
