/* =====================================================
   The Local Lab — story
   The page is one batch sheet read top to bottom: mở hàng at dawn, up to the farm,
   through the market, onto the bench, into the glass, out to the stool, and back to
   the corner. Each chapter pins its Vietnamese name on a file card, then the next
   sheet of paper slides up over it — perforated edge and all.
   ===================================================== */

/* ---------- the measurement rail ---------- */
.story-rail {
  position: fixed; left: max(10px, calc((100vw - var(--maxw)) / 2 - 34px)); top: 50%;
  transform: translateY(-50%); z-index: var(--z-head);
  display: grid; gap: 12px; align-items: center;
}
.story-rail .rail-line { width: 1px; height: 130px; background: var(--line); position: relative; overflow: hidden }
.story-rail .rail-fill { position: absolute; inset: 0; background: var(--accent); transform: scaleY(0); transform-origin: top }
.story-rail ol { list-style: none; display: grid; gap: 8px }
.story-rail button {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--mono); font-size: var(--step--2); line-height: 1; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); transition: color .3s var(--ease);
}
/* the ticks are graduated, not dotted — a scale you read a measurement off */
.story-rail button::before {
  content: ""; width: 8px; height: 1px; background: var(--line-strong);
  transition: width .3s var(--ease), background .3s var(--ease);
}
.story-rail button[aria-current="true"] { color: var(--text) }
.story-rail button[aria-current="true"]::before { background: var(--accent); width: 18px }
.story-rail button:hover { color: var(--accent) }
.story-rail button:hover::before { background: var(--accent) }
.story-rail .rail-vi { display: none; font-family: var(--body); font-weight: 700; letter-spacing: .02em }
.story-rail button:hover .rail-vi,
.story-rail button:focus-visible .rail-vi { display: inline }
@media (max-width: 1180px) { .story-rail { display: none } }

/* ---------- chapter shell ---------- */
.chapter { position: relative }
.chapter + .chapter { border-top: 1px solid var(--line) }

/* the pinned file card: it holds while the reader arrives, then the body slides over it */
.ch-pin {
  position: sticky; top: 0; height: var(--chapter-h);
  display: grid; align-content: center;
  padding-inline: var(--gutter); overflow: hidden;
}
/* the two rules a specimen card is printed between, and a registration corner */
.ch-pin::before {
  content: ""; position: absolute; left: var(--gutter); right: var(--gutter); top: 26px;
  height: 1px; background: var(--line); z-index: 1;
}
.ch-pin::after {
  content: ""; position: absolute; right: var(--gutter); bottom: 26px; width: 26px; height: 26px;
  border-right: 1px solid var(--line-strong); border-bottom: 1px solid var(--line-strong); z-index: 1;
}
.ch-pin-inner { max-width: var(--maxw); margin-inline: auto; width: 100%; position: relative; z-index: 2 }
.ch-num {
  font-family: var(--mono); font-weight: 400; font-size: var(--step-5);
  line-height: .8; letter-spacing: -.02em;
  color: transparent; -webkit-text-stroke: 1px var(--line-strong);
  position: absolute; right: 0; top: -16%; z-index: -1; pointer-events: none;
}
[data-theme="night"] .ch-num { -webkit-text-stroke-color: rgba(232, 234, 239, .34) }

/* the lot stamp, printed across the card's header rule: number, dotted leader, one
   measured figure — the same leader the hours list uses */
.ch-lot {
  display: flex; align-items: baseline; gap: .7rem;
  font: 400 var(--step--2)/1 var(--mono); letter-spacing: .18em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 1.3rem;
  /* the leader stops short of the outlined chapter numeral parked at the right edge,
     or the two collide and the stamp reads as noise */
  padding-inline-end: clamp(0px, 15vw, 210px);
}
.ch-lot i { flex: 1; border-bottom: 1px dotted var(--line-strong); transform: translateY(-.22em) }
.ch-pin.photo .ch-lot { color: rgba(232, 234, 239, .8) }
.ch-pin.photo .ch-lot i { border-bottom-color: rgba(232, 234, 239, .34) }

/* the chapter title pair: the English gloss sits over the Vietnamese name,
   which is the loudest type on the screen */
.ch-titles { display: grid; gap: .55rem; margin-bottom: 1.2rem }
.ch-titles .en-title, .ch-titles .vi-title { display: block }
.ch-titles .vi-title { max-width: 15ch }
.ch-titles .accent { color: var(--accent) }
/* the lede runs to 62ch and the note card is a narrow aside — without a gap they
   stack into one wall of type, which is worst on a phone where both wrap hard */
.ch-pin-inner > .note-card { margin-top: 1.15rem }

/* the paper sheet that scrolls up over the pinned card */
.ch-body {
  position: relative; z-index: 3;
  background: var(--bg);
  border-top: 2px solid var(--line-strong);
  padding-block: clamp(46px, 6vw, 88px) clamp(60px, 8vw, 120px);
}
/* the perforation strip of continuous-feed stock, along the leading edge */
.ch-body::before {
  content: ""; position: absolute; top: 6px; left: 0; right: 0; height: 6px;
  background-image: radial-gradient(circle, var(--line-strong) 1.5px, transparent 1.6px);
  background-size: 16px 6px; background-repeat: repeat-x;
  pointer-events: none;
}
.ch-body.alt { background: var(--bg-alt) }
/* the bench band is a fixed dark island, so it pins its own roles rather than
   inheriting whichever theme the reader happens to be in */
.ch-body.ink {
  --text: #E8EAEF; --muted: #99A1AE; --text-soft: #C3C9D3;
  --accent: var(--vermilion-on-dark); --accent-2: #7FB2E8; --accent-hover: #FF9470; --on-accent: #1A0C06;
  --surface: #181C22; --bg: #12161C; --gold-ink: #F0C24B;
  --line: rgba(232, 234, 239, .14); --line-strong: rgba(232, 234, 239, .36);
  --edge: rgba(232, 234, 239, .36); --grid: rgba(232, 234, 239, .05);
  background: #12161C; color: var(--text);
}
.ch-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2.1fr); gap: clamp(22px, 4vw, 56px); align-items: start }
@media (max-width: 900px) { .ch-grid { grid-template-columns: 1fr } }
.ch-aside { position: sticky; top: calc(var(--head-h) + 22px); display: grid; gap: 1.2rem }
@media (max-width: 900px) { .ch-aside { position: static } }

/* a pinned chapter whose card is a plate photograph of the room, not a sheet of paper */
.ch-pin.photo { color: #E8EAEF; --accent: var(--vermilion-on-dark) }
.ch-pin.photo .pin-scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(100deg, rgba(8, 10, 14, .94) 4%, rgba(8, 10, 14, .74) 46%, rgba(8, 10, 14, .3) 100%);
}
/* only the header rule carries a fill; the registration corner is two hairlines, and a
   background on it paints a solid square over the plate */
.ch-pin.photo::before, .ch-pin.photo::after { border-color: rgba(232, 234, 239, .3) }
.ch-pin.photo::before { background: rgba(232, 234, 239, .3) }
.ch-pin.photo .bleed-img { inset: -14% 0 }
.ch-pin.photo .en-title { color: var(--signal) }
.ch-pin.photo .vi-title { color: #F2F4F7 }
.ch-pin.photo .sec-lede { color: #C3C9D3 }
.ch-pin.photo .note-card { color: #D7DCE4; border-left-color: var(--signal) }
.ch-num.on-photo { -webkit-text-stroke-color: rgba(232, 234, 239, .5) }

/* the last chapter is pinned under lantern light rather than daylight */
.ch-pin.night-pin {
  background: #12161C;
  --text: #E8EAEF; --muted: #99A1AE; --text-soft: #C3C9D3;
  --accent: var(--signal); --line-strong: rgba(232, 234, 239, .4); --gold-ink: #F0C24B;
}
[data-theme="night"] .ch-pin.night-pin { background: #08090C }
.ch-pin.night-pin .ch-num { -webkit-text-stroke-color: rgba(232, 234, 239, .55) }
.ch-pin.night-pin::before, .ch-pin.night-pin::after { border-color: rgba(232, 234, 239, .28) }
.ch-pin.night-pin::before { background: rgba(232, 234, 239, .28) }
/* the lanterns are drawn like the tool plates in the appendix: a hairline silhouette
   with one warm filament, swinging on a cord */
.pin-lanterns { position: absolute; inset: 0 0 auto; height: 300px; pointer-events: none }
.pin-lanterns span {
  position: absolute; width: 24px; height: 32px; border-radius: 48% / 50%;
  border: 1px solid var(--gold-ink);
  background: radial-gradient(circle at 50% 38%, rgba(240, 194, 75, .6), rgba(194, 44, 18, .2) 74%);
  box-shadow: 0 0 26px 4px rgba(240, 194, 75, .2);
  transform-origin: top center; animation: lantern-sway 7s var(--ease) infinite;
}
.pin-lanterns span::before { content: ""; position: absolute; left: 50%; top: -40px; width: 1px; height: 40px; background: rgba(232, 234, 239, .3); translate: -50% 0 }
.pin-lanterns span:nth-child(1) { left: 12%; top: 34px; animation-delay: -.4s }
.pin-lanterns span:nth-child(2) { left: 26%; top: 8px; scale: .8; animation-delay: -1.6s }
.pin-lanterns span:nth-child(3) { left: 64%; top: 46px; scale: 1.2; animation-delay: -2.8s }
.pin-lanterns span:nth-child(4) { left: 76%; top: 12px; scale: .72; animation-delay: -4.1s }
.pin-lanterns span:nth-child(5) { left: 88%; top: 56px; animation-delay: -5.3s }
.pin-lanterns span:nth-child(6) { left: 44%; top: 22px; scale: .9; animation-delay: -6.2s }

/* the stool chapter: the argument on the left, the numbers on the right */
.stool-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: clamp(22px, 4vw, 54px); align-items: start }
@media (max-width: 900px) { .stool-grid { grid-template-columns: 1fr } }
.stool-copy { display: grid; gap: 1rem; justify-items: start; max-width: 62ch }
.stool-copy p { color: var(--muted) }
.stool-facts { list-style: none; display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line) }
.stool-facts li {
  display: grid; gap: .2rem; padding: .85rem 1rem;
  background: var(--surface); transition: background .3s var(--ease), box-shadow .3s var(--ease);
}
.stool-facts li:hover { background: color-mix(in srgb, var(--signal) 18%, var(--surface)); box-shadow: inset 0 0 0 1px var(--line-strong) }
.stool-facts b { font-family: var(--mono); font-size: var(--step-1); font-weight: 700; color: var(--accent); line-height: 1.1 }
.stool-facts span { font-size: .88rem; color: var(--muted) }

/* ---------- chapter one: the batch sheet ---------- */
.hero {
  position: relative; min-height: max(var(--chapter-h), min(100svh, 880px));
  display: grid; align-items: center;
  padding: calc(var(--head-h) + 30px) var(--gutter) 40px;
  overflow: hidden;
}
.hero-layers { position: absolute; inset: 0; z-index: 0; pointer-events: none }
.hero-photo {
  position: absolute; inset: -8% -4%;
  background: url("../assets/img/saigon-street-morning.jpg") center 40% / cover no-repeat;
  filter: saturate(.7) contrast(1.05);
  opacity: .18;
}
[data-theme="night"] .hero-photo { opacity: .26; filter: saturate(.5) brightness(.75) }
.hero-veil {
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 80% at 12% 30%, color-mix(in srgb, var(--signal) 22%, transparent), transparent 60%),
    linear-gradient(100deg, var(--bg) 8%, color-mix(in srgb, var(--bg) 80%, transparent) 46%, transparent 78%);
}
/* the desktop wash is sized for a wide sheet; on a phone the same radial spans the whole
   canvas, so the acid reads as a colour cast instead of a corner of morning light */
@media (max-width: 760px) {
  .hero-veil {
    background:
      radial-gradient(68% 30% at 6% 2%, color-mix(in srgb, var(--signal) 12%, transparent), transparent 72%),
      linear-gradient(100deg, var(--bg) 26%, color-mix(in srgb, var(--bg) 88%, transparent) 60%, color-mix(in srgb, var(--bg) 58%, transparent) 92%);
  }
}
.hero-lanterns { position: absolute; inset: 0 0 auto; height: 210px }
.hero-lanterns span {
  position: absolute; width: 26px; height: 34px; border-radius: 46% / 50%;
  border: 1px solid var(--gold-ink);
  background: radial-gradient(circle at 50% 40%, rgba(240, 194, 75, .7), rgba(194, 44, 18, .26) 74%);
  box-shadow: 0 0 28px 4px rgba(240, 194, 75, .22);
  transform-origin: top center; animation: lantern-sway 6s var(--ease) infinite;
}
.hero-lanterns span::before { content: ""; position: absolute; left: 50%; top: -26px; width: 1px; height: 26px; background: var(--line-strong); translate: -50% 0 }
.hero-lanterns span:nth-child(1) { left: 58%; top: -6px; animation-delay: -.6s }
.hero-lanterns span:nth-child(2) { left: 70%; top: 16px; scale: .8; animation-delay: -2.1s }
.hero-lanterns span:nth-child(3) { left: 82%; top: -14px; scale: 1.15; animation-delay: -3.4s }
.hero-lanterns span:nth-child(4) { left: 92%; top: 22px; scale: .7; animation-delay: -4.8s }
@keyframes lantern-sway { 0%, 100% { rotate: -4deg } 50% { rotate: 4deg } }

.hero-grid { position: relative; z-index: 1; max-width: var(--maxw); margin-inline: auto; width: 100%; display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: clamp(24px, 4vw, 60px); align-items: center }
@media (max-width: 1000px) { .hero-grid { grid-template-columns: 1fr } }

.hero-copy { display: grid; gap: 1.15rem; justify-items: start; padding-block: clamp(20px, 4vw, 44px) 20px }
.hero-title { font-size: clamp(2.4rem, 7vw, 5.4rem) }
.hero-lede { font-size: var(--step-0); color: var(--text-soft); max-width: 56ch }
.hero-cta { display: flex; flex-wrap: wrap; gap: .7rem }
.hero-stats { display: flex; flex-wrap: wrap; gap: clamp(18px, 3vw, 42px); border-top: 1px solid var(--line-strong); padding-top: 1rem; width: 100%; max-width: 34rem }
.hero-stats > div { display: grid; gap: .15rem }
.hero-stats dt { font-family: var(--mono); font-size: var(--step--2); font-weight: 400; letter-spacing: .16em; text-transform: uppercase; color: var(--muted) }
.hero-stats dd { font-family: var(--mono); font-weight: 700; font-size: var(--step-2); color: var(--accent); line-height: 1 }

/* kinetic opening type: each line is masked and lifts into place on boot */
.hero-title .line { display: block; overflow: hidden }
.hero-title .line > span { display: block; transform: translateY(104%); animation: line-rise .95s var(--ease) forwards }
.hero-title .line:nth-child(2) > span { animation-delay: .13s }
.hero-title .line:nth-child(3) > span { animation-delay: .26s }
@keyframes line-rise { to { transform: none } }

.hero-stack { position: relative; display: grid; gap: 16px; justify-items: center }
.hero-stack .note-card { max-width: 40ch; text-align: left }
.hero-shot { position: relative; width: 100%; display: grid; justify-items: center }
/* the hero plate is a photograph slipped into the report, squared and lightly tilted */
.hero-card {
  position: relative; width: min(100%, 420px);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--surface); padding: 10px; box-shadow: var(--shadow-lift);
  transform: rotate(-1.4deg); transition: transform .5s var(--ease-back);
}
.hero-card:hover { transform: none }
.hero-card img { border-radius: var(--r-sm); width: 100%; object-fit: cover; aspect-ratio: 4 / 5 }
.hero-card figcaption { padding: .75rem .2rem .1rem; display: grid; gap: .15rem }
.hero-card figcaption b { font-family: var(--display); font-size: 1.05rem; letter-spacing: -.02em }
.hero-card figcaption span { font-family: var(--mono); font-size: var(--step--1); color: var(--muted) }
/* the tags are specimen stickers: they keep their own fixed paper, not the theme's surface */
.hero-badge {
  position: absolute; z-index: 3; display: inline-flex; align-items: center; gap: .4rem;
  font-weight: 700; font-size: var(--step--2); line-height: 1; letter-spacing: .08em; text-transform: uppercase;
  padding: .45rem .7rem; border-radius: var(--r-sm); border: 1px solid var(--graphite);
  background: var(--paper); color: var(--graphite);
  animation: bob 5.5s var(--ease) infinite;
}
.hero-badge.b1 { left: -4%; top: 12%; animation-delay: -.4s }
.hero-badge.b2 { right: -3%; top: 42%; border-color: var(--vermilion); color: var(--vermilion); animation-delay: -1.9s }
.hero-badge.b3 { left: 6%; bottom: 12%; background: var(--signal); color: var(--on-signal); border-color: var(--signal-dim); animation-delay: -3.2s }
@keyframes bob { 0%, 100% { translate: 0 0 } 50% { translate: 0 -10px } }

.scroll-cue {
  display: inline-flex; align-items: center; gap: .6rem; margin-top: 1.6rem;
  font-family: var(--mono); font-size: var(--step--2); line-height: 1; letter-spacing: .2em; text-transform: uppercase; color: var(--muted);
}
.scroll-cue i { width: 1px; height: 34px; background: var(--line-strong); position: relative }
.scroll-cue i::after {
  content: ""; position: absolute; left: -2px; top: 0; width: 5px; height: 5px; border-radius: 1px;
  background: var(--accent); animation: cue 1.8s var(--ease) infinite;
}
@keyframes cue { 0% { opacity: 0; translate: 0 -4px } 30% { opacity: 1 } 100% { opacity: 0; translate: 0 28px } }

/* ---------- the phin drip (origin chapter) ---------- */
.phin { position: relative; width: 118px; height: 150px; margin-top: .4rem; color: var(--text) }
.phin svg { width: 100%; height: 100% }
.phin .drip { animation: drip 2.6s linear infinite; transform-origin: center }
.phin .drip.d2 { animation-delay: .9s }
.phin .drip.d3 { animation-delay: 1.8s }
@keyframes drip {
  0% { opacity: 0; transform: translateY(0) }
  12% { opacity: 1 }
  78% { opacity: 1; transform: translateY(46px) }
  100% { opacity: 0; transform: translateY(52px) }
}

/* ---------- the ruled floor (the stool chapter) ---------- */
.stage { position: relative; overflow: hidden }
.stage::after {
  content: ""; position: absolute; inset: auto 0 0; height: 30%;
  background: repeating-linear-gradient(180deg, var(--line) 0 1px, transparent 1px 9px);
  mask-image: linear-gradient(180deg, transparent, #000);
  pointer-events: none;
}

/* ---------- the contact sheet (gallery) ---------- */
.lantern-row {
  counter-reset: plate;
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(240px, 30vw);
  gap: clamp(12px, 1.4vw, 22px);
  overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
  padding: 6px var(--gutter) 26px;
  scrollbar-width: thin;
}
.lantern-row::-webkit-scrollbar { height: 6px }
.lantern-row::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 0 }
.lantern-row::-webkit-scrollbar-track { background: var(--line) }
.lantern-row .shot { scroll-snap-align: center; height: clamp(280px, 42vw, 460px) }
.lantern-row .shot .cap { opacity: 1; transform: none }
/* each frame gets the plate number a contact sheet would carry */
.lantern-row .shot::after {
  counter-increment: plate; content: "PL " counter(plate, decimal-leading-zero);
  position: absolute; top: 6px; left: 6px; z-index: 2;
  font: 400 var(--step--2)/1 var(--mono); letter-spacing: .12em;
  background: var(--graphite); color: var(--paper); padding: .12rem .3rem;
}
.row-hint { display: flex; align-items: center; gap: .6rem; font-family: var(--mono); font-size: var(--step--1); color: var(--muted); letter-spacing: .12em; text-transform: uppercase; font-weight: 400; margin-bottom: .9rem }

/* ---------- the guide ---------- */
.narrator {
  position: fixed; right: clamp(12px, 2vw, 26px); bottom: 104px; z-index: var(--z-narrator);
  display: flex; align-items: flex-end; justify-content: flex-end; gap: 12px;
  opacity: 0; transform: translateY(28px) scale(.94); pointer-events: none;
  transition: opacity .5s var(--ease), transform .5s var(--ease-back);
}
.narrator.on { opacity: 1; transform: none; pointer-events: auto }
.narrator.tuck { opacity: 0; transform: translateY(28px) scale(.94); pointer-events: none }
/* while the reader is actually moving the guide steps back so it never sits on top of
   a card they are trying to read; it comes forward again the moment the scroll stops */
.narrator.dim { opacity: .24; pointer-events: none; filter: saturate(.7) }

/* a note marked up in highlighter and stuck to the margin of the sheet */
.n-bubble {
  position: relative; max-width: min(300px, 42vw);
  background: var(--signal); color: var(--on-signal);
  border: 1px solid var(--graphite); border-radius: var(--r-sm);
  padding: .9rem 1rem .8rem; box-shadow: 4px 4px 0 rgba(20, 22, 26, .18);
  display: grid; gap: .5rem; justify-items: start;
}
.n-bubble::after {
  content: ""; position: absolute; right: -7px; bottom: 30px; width: 12px; height: 12px;
  background: var(--signal); border-top: 1px solid var(--graphite); border-right: 1px solid var(--graphite);
  transform: rotate(45deg);
}
.n-say { font-family: var(--script); font-size: 1.12rem; line-height: 1.45; color: var(--on-signal) }
.n-cta {
  display: inline-flex; align-items: center; gap: .4rem; text-decoration: none;
  font-weight: 700; font-size: var(--step--2); line-height: 1; letter-spacing: .1em; text-transform: uppercase;
  background: var(--vermilion); color: #FFF6F2; border: 1px solid var(--graphite);
  padding: .5rem .75rem; border-radius: var(--r-sm);
  transition: background .25s var(--ease), transform .2s var(--ease);
}
.n-cta:hover { background: var(--vermilion-deep); color: #FFF6F2 }
.n-close {
  position: absolute; top: -10px; left: -10px; width: 24px; height: 24px; border-radius: var(--r-sm);
  background: var(--paper); border: 1px solid var(--graphite); color: var(--graphite);
  font-size: .78rem; line-height: 1; display: grid; place-content: center;
  transition: background .2s var(--ease), color .2s var(--ease);
}
.n-close:hover { background: var(--vermilion); color: #FFF6F2 }

.n-figure { width: 108px; height: 128px; position: relative; flex: none; padding: 0; cursor: pointer; color: var(--text) }
.n-figure svg { width: 100%; height: 100%; overflow: visible }
.n-figure:hover .n-body { animation-duration: 1.6s }
/* the figure is drawn as a plate: strokes take the theme's ink, the coat takes the
   theme's paper, so it reads on specimen stock by day and on the dark bench by night */
.n-figure .f-line { stroke: var(--text); fill: none }
.n-figure .f-coat { fill: var(--surface); stroke: var(--text) }
.n-figure .f-skin { fill: #EFC29A; stroke: var(--text) }
.n-figure .f-hat { fill: #D9B65C; stroke: var(--text) }
.n-figure .f-stool { fill: var(--accent-2); stroke: var(--text) }
.n-figure .f-ink { fill: var(--text); stroke: none }
/* quiet: the note folds away and only the figure is left on the bench, still
   waving — click it and the guide comes back without a reload.
   folded is the same shape but transient: the guide says its line when a chapter
   starts, then steps back on its own so it never sits on top of a card you are reading. */
.narrator.quiet .n-bubble,
.narrator.folded .n-bubble { display: none }
.narrator.quiet .n-figure,
.narrator.folded .n-figure { width: 78px; height: 96px }
.n-figure .n-body { animation: bench-idle 4.6s var(--ease) infinite; transform-origin: 50% 90% }
@keyframes bench-idle { 0%, 100% { translate: 0 0; rotate: -1.2deg } 50% { translate: 0 -6px; rotate: 1.2deg } }
.n-figure .n-arm-wave { transform-origin: 74px 62px; animation: wave 2.8s var(--ease) infinite }
@keyframes wave { 0%, 62%, 100% { rotate: 0deg } 70% { rotate: -22deg } 78% { rotate: 8deg } 86% { rotate: -16deg } }
.n-figure .n-lid { transform-origin: center; animation: blink 6.5s steps(1, end) infinite }
@keyframes blink { 0%, 92%, 100% { transform: scaleY(1) } 94%, 98% { transform: scaleY(.08) } }
.narrator.pop .n-figure { animation: hop .62s var(--ease-back) }
@keyframes hop { 0% { scale: 1 } 38% { scale: 1.12 .92 } 100% { scale: 1 } }
.n-shadow { position: absolute; left: 50%; bottom: -6px; translate: -50% 0; width: 70px; height: 8px; background: var(--line); filter: blur(1px) }

@media (max-width: 760px) {
  .narrator { bottom: 92px; gap: 8px }
  .n-figure { width: 74px; height: 92px }
  .n-bubble { max-width: min(58vw, 250px); padding: .7rem .8rem .65rem }
  .n-say { font-size: .95rem }
}
@media (max-width: 430px) {
  .narrator { bottom: 86px }
  .n-bubble { max-width: 62vw }
}

/* ---------- closing band ---------- */
.marry {
  display: grid; place-items: center; text-align: center;
  padding-block: clamp(50px, 7vw, 96px);
}
.marry .wrap { display: grid; gap: 1rem; justify-items: center }
.marry .script { font-size: var(--step-3); line-height: 1.15; padding-bottom: .25rem; color: var(--signal) }
.marry p { max-width: 54ch; color: var(--muted) }
.marry-cta { display: flex; flex-wrap: wrap; gap: .7rem; justify-content: center; margin-top: .4rem }
