/* ===== HERO PHASE 2 ===== */

#hero .hero-stage { transition: transform 0.8s var(--ease-out); }
/* phase 2: wider browser slides left so its right edge stays on-screen */
body.hero-p2 #hero .hero-stage { transform: translateX(-5vw); }
/* P3 holds the stage where P2 left it: the in-browser text is the same words,
   so any shift reads as the text jumping */
body.hero-p3 #hero .hero-stage { transform: translateX(-5vw); }
/* P5: shift left + drop */
body.hero-p5 #hero .hero-stage { transform: translateX(calc(-5vw - 4.5%)) translateY(12px); }

#hero .browser {
  position: relative;                /* containing block for the absolute page layers */
  transform: perspective(1300px) rotateY(-4.4deg) scale(0.9);
  transform-origin: 50% 50%;
  transition: transform 0.8s var(--ease-out), box-shadow var(--dur-4) ease;
}
#hero .browser,
body.hero-p2 #hero .browser,
body.hero-p3 #hero .browser {
  width: min(630px, 43.5vw) !important;
  max-width: none !important;
}
body.hero-p2 #hero .browser { transform: perspective(1300px) rotateY(0deg) !important; }
body.hero-p3 #hero .browser { transform: perspective(1300px) rotateY(0deg) !important; }   /* flat, same as P2 — text doesn't tilt on the P2→P3 swap */
body.hero-p5 #hero .browser { transform: perspective(1300px) rotateY(0deg) !important; }   /* flat — same pose as Immerse */

/* ── realistic browser chrome: hero-only (hh- prefixed), scoped under #hero so
   the shared .browser/.bbar/.url component is untouched. The dots move up into
   the tab strip, so they're hidden in .bbar. */
#hero .browser .bbar .bdots { display: none; }
#hero .hh-tabstrip { display: flex; align-items: center; gap: 10px; padding: 8px 14px 0; background: #efe9dd; }
/* deliberately off-tier: inset hairline seating the tab into the fake browser chrome, not elevation */
#hero .hh-tab { display: flex; align-items: center; gap: 6px; background: #fff; border-radius: 7px 7px 0 0; padding: 6px 12px 6px 8px; max-width: 62%; box-shadow: 0 -1px 0 var(--line) inset; }
#hero .hh-tab-fav { width: 12px; height: 12px; border-radius: 3px; background: linear-gradient(155deg,#e0453a,#b3271d); flex: none; display: flex; align-items: center; justify-content: center; font: 700 7px var(--sans); color: #fff; }
#hero .hh-tab-title { font-size: var(--fs-micro); color: var(--ink-70); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* toolbar nav icons + extensions/avatar */
#hero .hh-nav-ico { width: 14px; height: 14px; color: var(--ink-45); flex: none; }
#hero .hh-nav-dim { opacity: .35; }
#hero .hh-ext-ico { width: 14px; height: 14px; color: var(--ink-45); opacity: .75; flex: none; }
#hero .hh-avatar { width: 16px; height: 16px; border-radius: var(--r-circle); background: linear-gradient(155deg,var(--amber-bright,#fbb03b),var(--amber-deep)); flex: none; display: flex; align-items: center; justify-content: center; font-family: var(--sans); font-weight: 700; font-size: 6.5px; letter-spacing: 0; color: #fff; }

/* hero photo — an editorial header (photo + headline on it); aspect-ratio
   scales it with the card's width. The vertical position picks which slice of
   the photo shows in this short strip. */
#hero .hh-hero-photo {
  aspect-ratio: 16 / 2.6; position: relative; overflow: hidden; display: flex; align-items: flex-end;
  background: #1a1310 url('hero-eras-photo.jpg') center 45% / cover no-repeat;
}
#hero .hh-hero-photo::before {
  content: ''; position: absolute; inset: 0;
  background-image: radial-gradient(rgba(255,255,255,.5) .5px, transparent .5px);
  background-size: 3px 3px; opacity: .1; mix-blend-mode: overlay;
}
#hero .hh-hero-photo::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 78%;
  background: linear-gradient(to top, rgba(10,7,4,.82) 0%, rgba(10,7,4,.5) 45%, transparent 100%);
}
#hero .hh-hp-text { position: relative; z-index: var(--z-base); padding: 10px 20px 9px; width: 100%; }
#hero .hh-hp-kicker { display: block; font: 700 8px var(--mono); letter-spacing: .12em; text-transform: uppercase; color: #f0b968; margin: 0 0 4px; }
/* byline beside the title, not under it — the line goes to a bigger title */
#hero .hh-hp-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 14px; }
#hero .hh-hp-title { margin: 0; font: 700 var(--fs-h4) var(--sans); letter-spacing: -.015em; line-height: 1.1; color: #fff; }
#hero .hh-hp-byline { flex: none; white-space: nowrap; font: 500 9px var(--sans); color: rgba(255,255,255,.75); padding-bottom: 2px; }
@media (max-width: 920px) {
  #hero .hh-hp-title { font-size: var(--fs-body); }
  #hero .hh-hp-kicker, #hero .hh-hp-byline { font-size: 8px; }
}

/* grounded shadow + hairline ring. !important overrides the inline box-shadow
   on the element and the .floatwrap filter in lantern-v3.css.
   deliberately off-tier: the page's largest surface needs its own depth. */
#hero .browser { box-shadow: 0 34px 60px -28px rgba(var(--ink-rgb),.4), 0 8px 18px -8px rgba(var(--ink-rgb),.16), 0 0 0 1px rgba(var(--ink-rgb),.04) !important; }
#hero .floatwrap { filter: drop-shadow(0 22px 34px rgba(58,36,2,.16)) drop-shadow(0 6px 14px rgba(var(--ink-rgb),.1)) !important; }

/* the tab strip, nav icons and photo header are desktop-only: phones keep the
   simple bbar (dots + url + exercise counter) */
@media (max-width: 920px) {
  #hero .hh-tabstrip, #hero .hh-hero-photo { display: none; }
  #hero .browser .bbar .bdots { display: flex; }
  #hero .browser .bbar .hh-nav-ico, #hero .browser .bbar .hh-ext-ico, #hero .browser .bbar .hh-avatar { display: none; }
  /* the desktop -40px pull would drag the smaller button over article text */
  #hero .hh-play-dock { margin-top: -8px; }
}
/* the photo header carries the headline, so each layer's own repeated title
   goes (desktop-only, where the photo shows) */
@media (min-width: 921px) {
  #hero .browser .page-en > p:first-child,
  #hero .browser .ex-page > p:first-child,
  #hero .browser .imm-page .imm-title {
    display: none;
  }
}

#hero .hero-copy {
  transition: opacity 0.5s ease, transform 0.65s var(--ease-out);
}
body.hero-p2 #hero .hero-copy {
  opacity: 0;
  transform: translateX(-100px);
  pointer-events: none;
}

#hero .hw-card { transition: transform 0.45s var(--ease-out), opacity 0.35s ease; }
body.hero-p2 #hero .hw-card  { opacity: 0 !important; pointer-events: none; }
#hero .hw-card .wordcard { transform: rotate(var(--rot, 0deg)); }
/* big word-cards drift gently in the air once they settle (overrides lantern-v3.css, which pinned them static) */
#hero .hw-card.rested { animation: card-bob var(--cbdur, 4.6s) ease-in-out infinite; animation-delay: var(--cbdel, 0s); }
.topbar { pointer-events: none; }
.topbar .brand, .topbar .pill { pointer-events: auto; }
/* scroll lock while the demo is live (lockPageScroll() in lantern-phases.js):
   the fixed hero chrome only hides via .past-hero, so a deliberate exit is
   the only way out */
html.hero-lock, body.hero-lock { overflow: hidden; }
/* topbar content rides the centred .wrap grid (max 1200), not the raw gutter;
   the background stays full-bleed, only the padding tracks the wrap inset */
.topbar { padding-left:  max(var(--gut), calc((100% - var(--maxw)) / 2 + var(--gut)));
          padding-right: max(var(--gut), calc((100% - var(--maxw)) / 2 + var(--gut))); }

#hero .hero-copy   { grid-column: 1; grid-row: 1; }
#hero .hero-stage  { grid-column: 2; grid-row: 1; position: relative; }

/* ═══ HOME hero, mobile look (.hh-wrap is .m-only) ═══ */
/* one amber payoff-word per phase title */
#hero .hero-copy-p2 h2 .hl-am,
#hero .hero-copy-imm h2 .hl-am, #hero .hero-copy-p5 h2 .hl-am { color: var(--amber-deep); }

.hh-scrim { position: absolute; inset: 0; background: rgba(52,44,28,.32); backdrop-filter: blur(1.8px); transition: .55s; }

/* PLAY lives in .hh-play-dock, in flow under the (overflow:hidden) .browser;
   the negative margin pulls it over the card's bottom edge as one cluster */
.hh-play-dock { display: none; flex-direction: column; align-items: center; gap: 10px; margin-top: -40px; }
/* amber circle + ink icon: the secondary "watch" action beside the black
   install CTAs. deliberately off-tier: an amber glow tinted to its own fill. */
.hh-play { position: relative; width: 46px; height: 46px; border-radius: var(--r-circle); border: 0; cursor: pointer; background: var(--amber-bright, #fbb03b); box-shadow: 0 14px 34px -8px rgba(191,110,12,.45); display: flex; align-items: center; justify-content: center; z-index: 6; transition: .18s; }
.hh-play:hover { transform: scale(1.06); }
.hh-play::before { content: ''; position: absolute; inset: -10px; border-radius: var(--r-circle); border: 2px solid rgba(var(--amber-rgb),.55); animation: hh-ppulse 2.4s ease-out infinite; }
@keyframes hh-ppulse { 0% { transform: scale(.85); opacity: .9; } 100% { transform: scale(1.45); opacity: 0; } }
.hh-play svg { fill: var(--ink); margin-left: 3px; width: 18px; height: 18px; }
.hh-playlabel { position: relative; z-index: 6; white-space: nowrap; font: 700 var(--fs-caption) var(--sans); color: #fff; background: rgba(20,15,5,.55); padding: 6px 11px; border-radius: var(--r-pill); backdrop-filter: blur(3px); }

/* mobile HOME poster over the browser under a big PLAY; shown only on Home at
   ≤920px, lifted (.home-live) once PLAY fires. The play dock follows the same
   visibility. */
#hero .hh-poster { display: none; }
body:not(.hero-p2):not(.hero-p3):not(.hero-imm):not(.hero-p5):not(.hero-simp) #hero .hh-play-dock { display: flex; }
body.home-live #hero .hh-play-dock { opacity: 0; pointer-events: none; transition: opacity .45s ease; }
/* desktop: no PLAY gate (lantern-deck.js starts step 0); out of the box model
   so Home lays out like every other step */
@media (min-width: 921px) { #hero .hh-play-dock { display: none !important; } }
/* the poster must read as a legible screenshot at once: no blur, a hint of tint */
#hero .hh-poster .hh-scrim { backdrop-filter: none; -webkit-backdrop-filter: none; background: rgba(246,244,240,.12); }
/* no idle sway while the poster shows — PLAY must not be a moving target */
body:not(.hero-p2):not(.hero-p3):not(.hero-imm):not(.hero-p5):not(.hero-simp):not(.home-live) #hero .floatwrap { animation: none !important; }

/* a still mimed frame behind the poster glass (sentence band, translate
   panel, quiz HUD). Hidden: without the blur it only occluded real text. */
.hh-life { display: none; }
.hh-life > * { position: absolute; display: block; }
.hl-band {
  left: 8%; top: 44.5%; width: 80%; height: 15px; border-radius: 3px;
  background: rgba(234,124,10,.38);
  transform-origin: 0 50%; transform: scaleX(1); opacity: .9;
}
.hl-tp {
  right: 5%; top: 13%; width: 62%; height: 84px; border-radius: var(--r-md);
  background: rgba(255,255,255,.98);
  /* deliberately off-tier: hairline ring + a warm-tinted shadow */
  box-shadow: 0 0 0 1px rgba(var(--ink-rgb),.07), 0 20px 40px -14px rgba(40,26,4,.6);
  opacity: 1; transform: none;
}
.hl-tp b { position: absolute; left: 13px; top: 12px; width: 34%; height: 8px; border-radius: var(--r-pill); background: rgba(var(--ink-rgb),.16); }
.hl-tp i { position: absolute; left: 13px; top: 40px; width: 74%; height: 9px; border-radius: var(--r-pill); background: rgba(var(--ink-rgb),.26); }
.hl-tp i.b { top: 60px; width: 56%; background: rgba(59,111,212,.5); }
.hl-hud {
  left: 0; right: 0; bottom: 0; height: 46px;
  background: rgba(253,252,250,.98); border-top: 1px solid rgba(var(--ink-rgb),.13);
  box-shadow: 0 -12px 26px -14px rgba(40,26,4,.4);   /* deliberately off-tier: upward shadow of a bar rising from the floor */
  opacity: 1; transform: none;
}
.hl-hud u { position: absolute; left: 14px; top: 11px; width: 36%; height: 11px; border-radius: var(--r-pill); background: rgba(var(--ink-rgb),.36); }
/* the track: 4 notches painted in, the fill over it */
.hl-hud s {
  position: absolute; left: 14px; right: 14px; bottom: 10px; height: 6px; border-radius: 3px;
  overflow: hidden; background:
    repeating-linear-gradient(90deg, rgba(var(--ink-rgb),.1) 0 calc(25% - 4px), transparent calc(25% - 4px) 25%);
}
.hl-hud s::after {
  content: ''; position: absolute; inset: 0; border-radius: 3px; background: var(--green, #2f9e5f);
  transform-origin: 0 50%; transform: scaleX(.5);
}
.hh-sheen { display: none; }

/* PLAY fades the mimed layer out before the real demo runs */
body.home-live #hero .hh-life { opacity: 0; transition: opacity .18s ease; }
body.home-live #hero .hh-life > *,
body.home-live #hero .hh-life s::after,
body.home-live #hero .hh-sheen { animation-play-state: paused; }

@media (max-width: 920px) {
  body:not(.hero-p2):not(.hero-p3):not(.hero-imm):not(.hero-p5):not(.hero-simp) #hero .hh-poster {
    display: block; position: absolute; inset: 0; z-index: 8; border-radius: inherit;
  }
  body.home-live #hero .hh-poster { opacity: 0; pointer-events: none; transition: opacity .45s ease; }
  /* .hh-poster nests inside .page, so inset:0 covers only the article body.
     The chrome's gutter matches the article's 20px — corrected on the chrome,
     since the article's padding would rewrap the hand-sized P1 paragraph. */
  #hero .browser .bbar { padding: 8.5px 20px; }
}

@media (min-width: 921px) {
  .hh-play { width: 68px; height: 68px; }
  .hh-play svg { width: 24px; height: 24px; }
  .hh-playlabel { font-size: var(--fs-eyebrow); padding: 7px 13px; }
  #hero .browser .hl { border-radius: var(--r-xs); padding: 0 2px; }
}


#hero .hero-copy-p2 {
  grid-column: 1; grid-row: 1;
  align-self: center; min-width: 0; max-width: 420px;
  opacity: 0; transform: translateY(56px); pointer-events: none;
  transition: opacity var(--dur-4) ease 0.18s, transform 0.72s var(--ease-out) 0.1s;
}
body.hero-p2 #hero .hero-copy-p2 { opacity: 1; transform: none; pointer-events: auto; }
#hero .hero-copy-p2 .p2-eyebrow,
#hero .hero-copy-imm .p2-eyebrow {
  font-family: var(--mono, 'JetBrains Mono', monospace);
  font-size: var(--fs-eyebrow); letter-spacing: .22em; text-transform: uppercase;
  color: var(--amber-deep, #bd6e0c); margin-bottom: 32px;
}
#hero .hero-copy-p2 h2,
#hero .hero-copy-imm h2 {
  font-weight: 700; letter-spacing: -.035em;
  font-size: clamp(32px, 3.5vw, 50px); line-height: 1.04; margin: 0 0 34px;
}
#hero .hero-copy-p2 .p2-sub,
#hero .hero-copy-imm .p2-sub,
#hero .hero-copy-p5 .p2-sub {
  font-size: clamp(15px, 1.5vw, 18px); color: var(--ink-70, rgba(var(--ink-rgb),.7));
  line-height: 1.58; max-width: 36ch; margin: 0;
}

/* HOME shows only the lead paragraph; this dense 2nd paragraph stays clipped away
   (clip-path + max-height:0) until SIMPLIFY (screen 2), where it reveals and gets
   simplified. overflow:visible lets the simp-dot peek out past the left edge. */
.hero-extra {
  overflow: visible;
  opacity: 0;
  max-height: 0;
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1s var(--ease-out) 0.12s, opacity 0.65s ease 0.3s, max-height 1s var(--ease-out) 0.12s;
}
body.hero-p2 .hero-extra {
  clip-path: inset(0 -10px -40px -34px); /* negative left lets dot peek out */
  max-height: 500px;
  opacity: 1;
}

.scroll-cue { transition: opacity 0.3s ease; display: none !important; }
body.hero-p2 .scroll-cue { opacity: 0; }

/* responsive visibility helpers */
.m-only { display: none; }
.d-only { display: block; }
/* .d-only would flatten .btn-install's inline-flex; two classes win it back.
   MUST stay behind min-width, or it also outranks the ≤920px `.d-only { display: none }`. */
@media (min-width: 921px) { .btn-install.d-only { display: inline-flex; } }
/* #hh-cta-dock is reparented out of .m-only by JS, so it needs its own desktop guard */
@media (min-width: 921px) { #hh-cta-dock { display: none !important; } }

/* worddeck: lift at-hero suppression in phase 2 */
body.hero-p2 #worddeck {
  opacity: 1 !important;
  pointer-events: auto !important;
  transition: opacity 0.35s ease, transform 0.5s var(--ease-out);
}

/* topbar stays transparent through every hero phase */
body.hero-p2.at-hero .topbar {
  background: transparent !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  box-shadow: none !important;
}
body.hero-p2.at-hero .topbar .nav-links {
  opacity: 1 !important; pointer-events: auto !important;
  transition: opacity 0.35s ease 0.2s;
}
/* the nav is reachable from screen 1 (lantern-v3.css hides it for the whole,
   permanently-on at-hero span) */
body.at-hero .topbar .nav-links { opacity: 1 !important; pointer-events: auto !important; }

/* leaving the demo (.past-hero, or .hero-exit-live from a plain scroll), the
   topbar solidifies and its pill reappears */
body.at-hero.past-hero .topbar, body.at-hero.hero-exit-live .topbar {
  background: rgba(242, 239, 233, .55);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 1px 0 rgba(var(--ink-rgb), .05);   /* deliberately off-tier: hairline separator under the topbar, not a lift */
}
body.at-hero.past-hero .pill { opacity: 1; visibility: visible; pointer-events: auto; }

/* ═══ DESKTOP SLIDE CONTROLS — ← [steps] → (lantern-deck.js) ═══
   On the ring pages the bar rides the page (absolute, in the hero's bottom
   band); on the wall and Install (fixed overlays) it pins to the viewport
   floor. Not a child of #hero: that goes opacity:0 on those two. */
#d-deck { display: none; }
@media (min-width: 921px) {
  #d-deck {
    position: absolute; left: 0; right: 0; top: calc(100vh - 88px);
    width: max-content; max-width: calc(100vw - 32px); margin: 0 auto;
    z-index: 71;
    display: flex; align-items: center; gap: 10px;
    transition: opacity var(--dur-3) ease;
  }
  body.ph-ev #d-deck, body.ph-cta #d-deck {
    position: fixed; top: auto; bottom: clamp(14px, 2.6vh, 24px);
    padding: 5px; border-radius: var(--r-pill);
    background: var(--paper, #f7f6f3);   /* solid, not frosted */
    box-shadow: var(--shadow-2);
  }
  /* the wall of cards: just the step name, no ← / → */
  body.ph-ev #d-deck .d-arrow { display: none; }
  /* the fixed pin must not follow the reader down the page */
  body.scrolled-off-hero #d-deck { opacity: 0; pointer-events: none; }
  body.scrolled-off-hero #d-deck * { pointer-events: none; }

  .d-rail { display: flex; align-items: center; gap: 2px; }
  .d-chap { position: relative; display: inline-flex; align-items: baseline; gap: 6px;
            background: none; border: none; margin: 0; padding: 8px 10px; border-radius: var(--r-pill);
            cursor: pointer; font-family: var(--mono, monospace); text-align: left;
            -webkit-tap-highlight-color: transparent; transition: background var(--dur-2) ease; }
  .d-chap-num { font-size: 9px; letter-spacing: .08em; color: var(--ink, #1a1714); opacity: .55;
                font-variant-numeric: tabular-nums; font-style: normal;
                transition: opacity .3s ease, color .3s ease; }
  /* every step is named, the inactive ones quietly */
  .d-chap-name { font-size: var(--fs-caption); letter-spacing: .13em; text-transform: uppercase;
                 color: var(--ink, #1a1714); opacity: .62; white-space: nowrap;
                 transition: opacity .35s ease, color .35s ease; }
  .d-chap:hover { background: rgba(var(--ink-rgb), .08); }
  .d-chap:hover .d-chap-name { opacity: 1; }
  .d-chap:focus-visible { outline: 2px solid var(--amber, #ef8e1c); outline-offset: 1px; }
  .d-chap.passed .d-chap-num { opacity: 1; color: var(--amber-deep, #bd6e0c); }
  /* the lit step's background and name colour: lantern-hero-ring-layout.css */
  .d-chap.on .d-chap-num { opacity: 1; color: var(--amber-bright, #fbb03b); }
  .d-chap.on .d-chap-name { opacity: 1; font-weight: 600; }

  /* ← / → — ink discs, glyph in the headline's amber */
  .d-arrow { position: relative; flex: none; width: 42px; height: 42px; border-radius: var(--r-circle);
             border: 0; padding: 0; cursor: pointer; background: var(--ink, #1a1714); color: #fff;
             display: inline-flex; align-items: center; justify-content: center;
             box-shadow: var(--shadow-2); transition: transform var(--dur-2) var(--ease-soft), opacity var(--dur-2) ease, box-shadow var(--dur-2) ease; }
  .d-arrow svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2.2;
                 stroke-linecap: round; stroke-linejoin: round; color: var(--amber-deep); }
  /* hover run-through (lantern-deck.js ARROW): the arrow drives off, clipped,
     its twin drives in; ← mirrors the box. Leaving the hover plays no drive
     back — the base rules fade, the :hover rules move. */
  .d-arrow-in { position: absolute; inset: 0; overflow: hidden; border-radius: 50%; }
  .d-arrow-in svg { position: absolute; top: 50%; left: 50%; margin: -9px 0 0 -9px;
                    transition: transform 0s, opacity .15s ease; }
  .d-arrow-in svg + svg { transform: translateX(-34px); opacity: 0;
                          transition: opacity .15s ease, transform 0s linear .15s; }
  .d-arrow:hover:not([aria-disabled="true"]) .d-arrow-in svg:first-child {
    transform: translateX(34px); opacity: 0;
    transition: transform .42s cubic-bezier(.3, 0, .2, 1), opacity 0s linear .42s;
  }
  .d-arrow:hover:not([aria-disabled="true"]) .d-arrow-in svg + svg {
    transform: none; opacity: 1;
    transition: transform .42s cubic-bezier(.3, 0, .2, 1) .08s, opacity 0s linear .08s;
  }
  /* pressed: hold the run-through's end state while the slide hides :hover
     (lantern-deck.js holdRan) — no replay when the hover comes back */
  .d-arrow.ran .d-arrow-in svg:first-child { transform: translateX(34px); opacity: 0; transition: none; }
  .d-arrow.ran .d-arrow-in svg + svg { transform: none; opacity: 1; transition: none; }
  .d-prev .d-arrow-in { transform: scaleX(-1); }
  @media (prefers-reduced-motion: reduce) { .d-arrow-in svg { transition: none; } }
  .d-arrow:active:not([aria-disabled="true"]) { transform: scale(.93); }
  .d-arrow:focus-visible { outline: 2px solid var(--amber, #ef8e1c); outline-offset: 3px; }
  /* first/last step: an ink outline. aria-disabled, not [disabled]: a disabled
     button drops keyboard focus to <body> */
  .d-arrow[aria-disabled="true"] { background: transparent; color: var(--ink, #1a1714); opacity: .35;
                      box-shadow: inset 0 0 0 2px var(--ink, #1a1714); cursor: default; }
  /* "the scene just finished — go on": two amber rings off the → disc (the
     show*Next hooks in lantern-phases.js) */
  .d-arrow.cue::before { content: ''; position: absolute; inset: -4px; border-radius: inherit;
                         border: 2px solid rgba(var(--amber-rgb), .6); pointer-events: none;
                         animation: d-cue 1.6s ease-out 2; }
  @keyframes d-cue { 0% { transform: scale(.9); opacity: 1; } 100% { transform: scale(1.5); opacity: 0; } }
  /* a press queued while a scene holds the wheel: the disc dims and a ring
     runs round it until the step goes through (lantern-deck.js press/drain) */
  .d-arrow.wait { opacity: .6; }
  .d-arrow.wait::after { content: ''; position: absolute; inset: -5px; border-radius: inherit;
                         border: 2px solid transparent; border-top-color: var(--amber, #ef8e1c);
                         animation: d-wait .8s linear infinite; pointer-events: none; }
  @keyframes d-wait { to { transform: rotate(360deg); } }
  @media (prefers-reduced-motion: reduce) {
    .d-arrow.cue::before { animation: none; opacity: 1; transform: scale(1.12); }
    .d-arrow.wait::after { animation: none; border-color: var(--amber, #ef8e1c); }
  }

  /* the Next pills are the mobile reel's control; on desktop the → arrow does their job */
  .tc-next { display: none !important; }

  /* the desktop hero is the ring (lantern-hero-ring-*.css). What stays here:
     the flat, untilted mock and the word cards' and MY VOCAB rail's sizes
     (every flight measures live rects, so they land on these sizes). The
     !important --rot beats the inline one the cards are built with. */
  #hero .browser { transform: none; }
  #hero .hw-card .wordcard { --rot: 0deg !important; padding: 12px 15px; border-radius: var(--r-lg); }
  #hero .hw-card .wordcard .wtop { gap: 8px; }
  #hero .hw-card .wordcard .tr { font-size: var(--fs-body); margin-top: 5px; }
  #hero .hw-card .wordcard .cefr-b { font-size: 9px; padding: 2px 5px; }
  #worddeck { right: clamp(16px, calc(50vw - 790px), 160px); width: 128px; }
  #worddeck .wd-card { padding: 7px 9px; gap: 6px; border-radius: var(--r-md); }
  #worddeck .wd-w { font-size: 14px; }
  #worddeck .wd-tr { font-size: var(--fs-micro); }
  #worddeck .wd-prog { width: 17px; height: 17px; }
  #worddeck .wd-card .cefr-b { font-size: 8px; padding: 1px 4px; }
  /* the wall→dock hand-off (lantern-everywhere.js toCTA) is flat: the article
     face cross-fades into the feature face (JS drives the opacities) */
  .flip-clone:not(.m-flip) { perspective: none; }
  .flip-clone:not(.m-flip) .fc-back { transform: translate(-50%, -50%); opacity: 0; }

  /* no scroll lock on desktop: scrolling off the hero takes the wall with it */
  body.ph-ev.scrolled-off-hero #finale { opacity: 0; pointer-events: none; }
  /* safety net: Install must never sit over the page off the hero. !important
     beats the scroll-out choreography's inline opacity (lantern-cta-charge.js) */
  body.ph-cta.scrolled-off-hero #ev-close { opacity: 0 !important; pointer-events: none !important; }   /* outranks body.ph-ev #finale further down */

  /* the install screen's two quiet exits: move on (.d1-exit) or replay (.d1-again) */
  .d1-exit, .d1-again { display: inline-flex; align-items: center; gap: 6px; margin-top: 22px;
             background: none; border: none; padding: 6px 10px; cursor: pointer;
             font-family: var(--mono, monospace); font-size: var(--fs-micro); letter-spacing: .1em;
             text-transform: uppercase; color: var(--ink, #1a1714); opacity: .38;
             border-radius: var(--r-pill); transition: opacity .3s ease, color .3s ease; }
  .d1-exit svg, .d1-again svg { width: 13px; height: 13px; }
  .d1-exit:hover, .d1-again:hover { opacity: .8; color: var(--amber-deep, #bd6e0c); }
  .d1-exit:focus-visible,
  .d1-again:focus-visible { outline: 2px solid var(--amber, #ef8e1c); outline-offset: 3px; opacity: .8; }
  /* it follows the exit directly — one tight pair, not two separate stops */
  .d1-exit + .d1-again { margin-top: 6px; }
  .d1-again .rew { color: var(--amber, #ef8e1c); font-size: var(--fs-eyebrow); line-height: 1; }
}

/* hero simplify dot: fade in after text is visible; on hover it eases up a touch
   (smooth, no bounce). transform MUST be in this transition list — this id rule
   overrides .simp-dot's own transform transition from lantern-v3.css, so without
   it the hover scale would snap instantly. */
#hero-simp-dot {
  opacity: 0; pointer-events: none;
  left: -12px; /* .simp-dot's base -16px sat only ~9px off the browser's rounded
                  edge here — a couple more px of breathing room */
  transition: opacity 0.35s ease 1s,
              transform 0.3s cubic-bezier(.25,.8,.35,1),
              box-shadow 0.3s ease, background 0.3s ease;
}
body.hero-p2 #hero-simp-dot { opacity: 1; pointer-events: auto; }
/* …but never in P3/P4 (hero-p2 stays on body there): the dot is invisible yet an explicit
   pointer-events:auto re-enables hit-testing through the page-en's pointer-events:none */
body.hero-p3 #hero-simp-dot { pointer-events: none !important; }
/* hover the dot → light amber wash hints "this paragraph will simplify",
   and the dot itself scales up smoothly */
#hero .sv-para.simp { border-radius: var(--r-sm); transition: background var(--dur-2) ease; }
#hero .sv-para.simp:has(#hero-simp-dot:hover) { background: rgba(var(--amber-rgb),0.10); }
/* the simplified wash takes exactly the hover box above — no 6px/10px bleed
   past the paragraph (owner 2026-09-27: "the same size as the hover") */
#hero .simp-body { padding: 0; margin: 0; border-radius: var(--r-sm); }
#hero .simp-ghost { padding: 0; } /* sits on the old text, same box */
#hero-simp-dot:hover { transform: translate(-50%,-50%) scale(1.35); }

/* reading-level badge pinned to the toolbar's top-right corner: pops in as C1,
   then flips to B2. left/bottom:auto undo lantern-v3.css's base .simp-level. */
.browser .url { position: relative; }
.browser .bbar { position: relative; }
.browser .simp-level {
  position: absolute; right: 24px; top: 50%; left: auto; bottom: auto;
  display: block; width: 34px; height: 22px;
  transform-origin: right center;
  opacity: 0; transform: translateY(-50%) scale(.5);
  transition: opacity .3s ease, transform .5s cubic-bezier(.2,1.12,.3,1);
  pointer-events: none; z-index: 4;
  perspective: 240px;                 /* gives the flip its depth */
}
.browser .simp-level.show { opacity: 1; transform: translateY(-50%) scale(1); }

/* the flipping card: two faces back-to-back, rotated on rolled */
.browser .simp-level .sl-flip {
  position: relative; width: 100%; height: 100%;
  transform-style: preserve-3d;
  transition: transform .62s cubic-bezier(.4,.05,.2,1);
}
.browser .simp-level.rolled .sl-flip { transform: rotateY(180deg); }
.browser .simp-level .sl-face {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--mono,'JetBrains Mono',monospace);
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .04em;
  border-radius: var(--r-sm);                 /* rounded-rect corners, matching the CEFR chips on the MY VOCAB cards */
  backface-visibility: hidden; -webkit-backface-visibility: hidden;
}
/* front = C1 (dense), amber */
.browser .simp-level .sl-front {
  color: var(--amber-deep,#bd6e0c); background: rgba(176,106,44,.10);
  border: 1px solid rgba(176,106,44,.3);
}
/* back = B2 (your level), green — pre-rotated so it faces out after the flip */
.browser .simp-level .sl-back {
  color: #fff; background: var(--green,#2f9e5f); border: 1px solid var(--green,#2f9e5f);
  transform: rotateY(180deg);
}
.browser .simp-level.rolled.pulse .sl-back { animation: slpulse .72s ease; }

/* ===== HERO PHASE 3 — Translate ===== */

/* all article layers stay position:absolute — crossfades, no layout shifts.
   The hero article reads one notch larger than the generic .browser mock. */
#hero .browser .page { position: relative; font-size: 16.5px; line-height: 1.72; min-height: 220px; overflow: hidden; transition: min-height 1s var(--ease-out) 0.12s; }
/* HOME: the window hugs its article (the paragraph takes 4 / 5 / 6 lines as
   the card narrows); every phase class sets its own min-height */
@media (min-width:  921px) { #hero { --home-page-h: 222px; } }
@media (min-width: 1000px) { #hero { --home-page-h: 194px; } }
@media (min-width: 1150px) { #hero { --home-page-h: 166px; } }
body:not(.hero-p2):not(.hero-p3):not(.hero-imm):not(.hero-p5):not(.hero-simp) #hero .browser .page {
  min-height: var(--home-page-h, 220px);
}
/* P2: browser expands smoothly as the 2nd paragraph reveals — min-height drives height, pages stay absolute */
body.hero-p2 #hero .browser .page { min-height: 340px; }
/* P5 (hero-p2 stays on through it): text + the 70px #hx-hud anchored to the
   page bottom + clearance. Must come AFTER the hero-p2 rule (same specificity). */
body.hero-p5 #hero .browser .page { min-height: 236px; }

#hero .page-en {
  position: absolute; top: 0; left: 0; right: 0;
  overflow: visible;
  transition: opacity 0.26s ease;
}
body.hero-p3 #hero .page-en { opacity: 0; pointer-events: none; transition: opacity 0.20s ease; }

/* .hl carries 3px side padding, pulled back with negative margins so the text
   flows exactly like plain text */
#hero .page-en .hl { margin: 0 -3px; }

/* p2 copy exits */
body.hero-p3 #hero .hero-copy-p2 { opacity: 0; transform: translateX(-120px); pointer-events: none; }

/* hero-p3 (on through Immerse and Practice): the browser's bob stays frozen */
body.hero-p3 #hero .floatwrap { animation: none !important; transform: none !important; }

/* the demo pointer that flies in to "click" the sentence open — viewport-fixed so
   it tracks the live sentence rect (reuses .hw-cursor visuals; hidden ≤1000px) */
.hw-cursor.tr-cursor { position: fixed; z-index: 62; }

/* "go next" pill — fades in and bobs once the scene has played; click → next
   screen. Ink, keeping amber for the one thing that converts. */
.tc-next {
  position: fixed; left: 0; top: 0; z-index: var(--z-overlay);
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 17px;
  font-family: var(--sans); font-size: var(--fs-sm); font-weight: 600; letter-spacing: .01em;
  color: #fff;
  background: var(--ink, #1a1714);
  border: 1px solid transparent; border-radius: var(--r-pill);
  box-shadow: var(--shadow-2);        /* floating bar: the one parked control */
  cursor: pointer;
  opacity: 0; transform: translateY(6px);
  /* NOTE: no `transform` in the transition — the bob + press keyframes own
     transform; a .4s transform transition would fight the keyframes at every
     bob→press handoff and make the auto-press jitter instead of depress cleanly */
  transition: opacity .3s ease, box-shadow .2s ease;
  pointer-events: none;
  /* clips .tc-fill (and the mobile crank gauge) to the pill's rounded ends */
  overflow: hidden;
}
/* auto-advance fill (armAutoAdvance drives the width). A child, not a pseudo:
   ::before/::after belong to the mobile crank gauge. */
.tc-fill {
  position: absolute; left: 0; bottom: 2px; width: 0%; height: 2px;
  background: var(--amber, #ef8e1c);
  pointer-events: none;
}
/* left/top transition only on .show: an invisible pill's first placement is instant */
.tc-next.show {
  opacity: 1; pointer-events: auto; animation: tcNextBob 2.4s ease-in-out infinite;
  transition: opacity .3s ease, box-shadow .2s ease, left .5s var(--ease-out), top .5s var(--ease-out);
}
.tc-next:hover { box-shadow: var(--shadow-3); }   /* one tier above its own rest (--shadow-2) */
.tc-next .arr { color: var(--amber, #ef8e1c); font-weight: 700; transition: transform var(--dur-2) ease; }
.tc-next:hover .arr { transform: translateX(3px); }
@keyframes tcNextBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
/* tactile press: a quick depress + amber ripple, over the bob */
.tc-next.press { animation: tcNextPress .28s ease; }
/* translateY(0) at every stop keeps the handoff to the bob seamless. Mid-press
   drops to --shadow-1 on purpose — a depress reads as lower. */
@keyframes tcNextPress {
  0%   { transform: translateY(0) scale(1);   box-shadow: var(--shadow-2), 0 0 0 0 rgba(var(--amber-rgb),.5); }
  32%  { transform: translateY(0) scale(.93); box-shadow: var(--shadow-1), 0 0 0 4px rgba(var(--amber-rgb),.32); }
  100% { transform: translateY(0) scale(1);   box-shadow: var(--shadow-2), 0 0 0 12px rgba(var(--amber-rgb),0); }
}
@media (prefers-reduced-motion: reduce) { .tc-next.show { animation: none; transition: opacity .3s ease, box-shadow .2s ease; } }
/* desktop berth: inert while .tc-next is display:none on desktop. Centred by
   margin auto, not translateX (the bob/press keyframes own transform);
   !important beats the inline left/top that place*Next() still writes. */
@media (min-width: 921px) {
  .tc-next {
    left: 0 !important; right: 0 !important;
    top: auto !important;
    bottom: 86px !important;
    width: max-content;
    margin-left: auto; margin-right: auto;
  }
}
/* short viewports: the mock browser is capped so it bottoms out above the berth */
@media (min-width: 921px) and (max-height: 860px) {
  #hero .browser { max-height: calc(100vh - 305px); }
}
/* mobile: bigger tap target. No box-shadow override — it would pop at every
   press handoff. */
@media (max-width: 920px) {
  .tc-next {
    padding: 12px 20px; font-size: var(--fs-body);
    /* one parked berth for every Next pill, anchored by edges (the keyframes
       own transform). The 104px right inset is the crank's throw (100px) + 4px;
       --m-next-btm and z-index 65 keep it above the bottom #worddeck strip. */
    --m-next-btm: calc(env(safe-area-inset-bottom, 0px) + 108px);
    z-index: 65 !important;
    left: auto !important;
    right: calc(env(safe-area-inset-right, 0px) + 104px) !important;
    top: auto !important;
    bottom: var(--m-next-btm) !important;
  }
  /* Home has no #worddeck strip to clear: its pill sits lower, making room for
     the saved-word cards to be pushed down into their row */
  #hero-home-next { bottom: calc(env(safe-area-inset-bottom, 0px) + 48px) !important; }
}

/* ═══ THE CRANK (mobile ≤920px) — the parked Next pill is also a drag handle
   (lantern-crank.js). Transform on the pill only, nothing on .stage (that
   would re-root the Immerse 3D flip). @property makes --crank / --gauge animate. */
@property --crank { syntax: '<length>'; inherits: false; initial-value: 0px; }
/* --gauge MUST inherit: JS sets it on .tc-next, the fill is drawn on its ::after */
@property --gauge { syntax: '<number>'; inherits: true; initial-value: 0.125; }
@media (max-width: 920px) {
  /* touch-action:none on the handle only, so a pull never scrolls the page */
  .tc-next { touch-action: none; overflow: hidden; }
  /* while a pull is live we own transform; .crank-return eases --crank back to 0 */
  .tc-next.crank-live { animation: none !important; transform: translate3d(var(--crank, 0px), 0, 0) !important; }
  .tc-next.crank-return { transition: --crank .28s cubic-bezier(.16, 1, .3, 1); }

  /* first-run hint: one 8px lean right and back, over the bob */
  .tc-next.crank-hint { animation: crankHint var(--dur-4) cubic-bezier(.34, 1.3, .64, 1) !important; }
  @keyframes crankHint {
    0%, 100% { transform: translateX(0); }
    45%      { transform: translateX(8px); }
  }

  /* in-pill gauge: an edge-to-edge hairline near the bottom (at bottom:0 the
     radius would swallow it); amber past the commit threshold (.crank-armed) */
  .tc-next::before {
    content: ''; position: absolute; left: 0; right: 0; bottom: 6px; height: 1.5px;
    background: rgba(250, 247, 242, .14); pointer-events: none;
  }
  .tc-next::after {
    content: ''; position: absolute; left: 0; bottom: 6px; height: 1.5px;
    width: calc(100% * var(--gauge, .125));
    background: rgba(250, 247, 242, .55); pointer-events: none;
    transition: width .24s cubic-bezier(.16, 1, .3, 1), background-color .12s linear;
  }
  .tc-next.crank-armed::after { background: var(--amber, #ef8e1c); }
  /* while the finger is down the fill tracks the drag 1:1 */
  .tc-next.crank-live:not(.crank-return)::after { transition: none; }

  @media (prefers-reduced-motion: reduce) {
    .tc-next.crank-return { transition: none; }
    .tc-next::after { transition: none; }
  }
}
/* ===== HERO PHASE 3.5 — Immersion (read the whole article in your language) =====
   Builds on the Translate browser. The article is a 3D flip card: the front face
   is English with our saved words in blue; the ↻ control flips it once and the
   back face shows the same article in the chosen gloss language, our words in
   violet. */
#hero .imm-page {
  position: absolute; top: 0; left: 0; right: 0;
  padding: 26px 32px; perspective: 1400px;
  opacity: 0; pointer-events: none; transition: opacity 0.28s ease;
}
body.hero-imm #hero .imm-page { opacity: 1; pointer-events: auto; }

#hero .imm-surface { position: relative; min-height: 196px; }
#hero .imm-face { top: 0; left: 0; right: 0; }
#hero .imm-front { position: relative; }
#hero .imm-back  { position: absolute; opacity: 0; pointer-events: none; }
/* per-word morph — each word transitions as a unit */
#hero .imm-word { display: inline-block; transition: opacity 0.22s ease, transform 0.27s var(--ease-soft); }
#hero .imm-face.imm-out .imm-word { opacity: 0; transform: translateY(-7px); }
#hero .imm-face.imm-in  .imm-word { opacity: 0; transform: translateY(7px); transition: none; }
#hero .imm-title { font-family: 'General Sans', sans-serif; font-weight: 700; font-size: var(--fs-lead); margin: 0 0 14px; padding: 3px 0; text-align: center; }
#hero .imm-p  { margin: 0; }
/* our saved words, marked on both faces — blue in English, violet once translated */
#hero .imm-w { border-radius: var(--r-xs); padding: 0 3px; transition: background var(--dur-2), color var(--dur-2); }
#hero .imm-front .imm-w { background: #e3edfd; color: #2f6fd6; }
#hero .imm-back  .imm-w { background: #efe4fb; color: #7b46cf; }
/* plain text: on Practice only the quiz gaps are marked */
#hero .ex-saved { background: none; color: inherit; }

/* ↻ flip control — reuses the in-browser pill; bottom-right like Discuss */
#hero-imm-fab {
  opacity: 0; transform: translateY(10px); pointer-events: none; z-index: 6;
  transition: opacity 0.3s ease, transform 0.38s cubic-bezier(.2,.85,.25,1);
  border-radius: var(--r-pill);
}
#hero-imm-fab.show { opacity: 1; transform: none; pointer-events: auto; }
#hero-imm-fab.press { transform: scale(.93); transition: transform 0.12s ease; }
#hero-imm-fab.gone  { opacity: 0; transform: scale(.9); pointer-events: none; transition: opacity 0.22s ease, transform var(--dur-2) ease; }
#hero-imm-fab .dc-ico { color: var(--amber-deep, #bd6e0c); }
/* the icon spins with the page each way it swaps (forward into your language,
   back into English) */
#hero-imm-fab .dc-ico svg { transition: transform 1s cubic-bezier(.52,0,.18,1); }
body.imm-flipped #hero-imm-fab .dc-ico svg { transform: rotate(360deg); }

/* Immersion copy — slides in from the right like the other phase copies */
#hero .hero-copy-imm {
  grid-column: 1; grid-row: 1; align-self: center; min-width: 0; max-width: 420px;
  opacity: 0; transform: translateX(120px); pointer-events: none;
  transition: opacity var(--dur-4) ease 0.12s, transform 0.72s var(--ease-out) 0.08s;
}
body.hero-imm #hero .hero-copy-imm { opacity: 1; transform: none; pointer-events: auto; }

@media (max-width: 920px) {
  /* width:100%, not 90vw — see the .hero-copy rule in the ≤920px block below:
     90vw overflows #hero's 100vw-48px column and drags the grid track with it. */
  #hero .hero-copy-imm { grid-column: 1 !important; grid-row: 1 !important; width: 100% !important; max-width: none !important; padding: 0; min-width: 0; align-self: end !important; transform: none; }
  body.hero-imm #hero .hero-copy-imm { transform: translateY(-12px); }
  #hero .hero-copy-imm h2 { display: block !important; white-space: normal; font-size: clamp(24px, 8vw, 31px) !important; margin-bottom: 0; line-height: 1.12; font-weight: 700; }
  #hero .hero-copy-imm .p2-eyebrow { font-size: var(--fs-micro); letter-spacing: .18em; margin-bottom: 8px; }
  #hero .hero-copy-imm .p2-sub { display: -webkit-box !important; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; margin: var(--m-vgap) auto 0 !important; max-width: none; font-size: var(--fs-read) !important; line-height: 1.45; }
  /* same floor as body.hero-p2's mobile min-height */
  body.hero-imm #hero .browser .page { min-height: 330px !important; }
  /* Immerse reads at the same size as the other article screens (.page-en);
     fitMobileBrowser() sizes the window to its content */
  #hero .imm-page { padding: 18px 20px 26px !important; }
  #hero .imm-title { font-size: var(--fs-lead) !important; margin: 0 0 12px !important; }
  #hero .imm-p { font-size: var(--fs-body) !important; line-height: 1.6 !important; }
  body.hero-imm #hero .imm-surface { min-height: auto !important; }
}

/* the window hugs the article: no floor under the last line */
body.hero-imm #hero .imm-surface { min-height: 0; }

/* "word used" credit: a spark flies from the word to its deck card, whose
   progress ring ticks up. Raised by Immerse (imm-w) and Practice. */
.use-spark {
  position: fixed; z-index: 96; width: 10px; height: 10px; border-radius: var(--r-circle);
  margin: -5px 0 0 -5px; pointer-events: none;
  /* deliberately off-tier: 0 0 0 Npx green halo ring around the spark, not elevation */
  background: var(--green, #2f9e5f); box-shadow: 0 0 0 4px rgba(47,158,95,.18);
  transition: transform 0.55s cubic-bezier(.3,.1,.3,1), opacity 0.2s ease 0.4s;
}

/* progress ring 3D pop when a word is used. On the ring, NOT the card: a
   card-level fill:both transform would stick and kill its tilt + hover lift. */
@keyframes ring-pop {
  0%   { transform: none; }
  38%  { transform: perspective(72px) translateZ(5px) scale(1.16); }
  100% { transform: none; }
}
.wd-card.ring-pop .wd-prog { animation: ring-pop 0.52s cubic-bezier(.2,.85,.3,1) both; }

/* mobile mastery bar: blinks twice as the flying chip arrives (the ring-pop's twin) */
@keyframes mr-bar-blink {
  0%   { transform: scaleY(1);   filter: brightness(1)    drop-shadow(0 0 0   rgba(var(--amber-rgb),0));  }
  18%  { transform: scaleY(1.8); filter: brightness(1.38) drop-shadow(0 0 4px rgba(var(--amber-rgb),.85)); }
  40%  { transform: scaleY(1);   filter: brightness(1)    drop-shadow(0 0 0   rgba(var(--amber-rgb),0));  }
  60%  { transform: scaleY(1.6); filter: brightness(1.34) drop-shadow(0 0 4px rgba(var(--amber-rgb),.8));  }
  100% { transform: scaleY(1);   filter: brightness(1)    drop-shadow(0 0 0   rgba(var(--amber-rgb),0));  }
}
.mr-bar-blink { animation: mr-bar-blink 0.66s cubic-bezier(.2,.85,.3,1) both; }

/* once the page scrolls past the hero to the CTA, hero chrome bows out */
body.past-hero #worddeck { opacity: 0 !important; pointer-events: none !important; transition: opacity 0.3s ease; }
/* desktop slides: no .past-hero there — the fixed vocab deck leaves with the hero */
@media (min-width: 921px) {
  body.scrolled-off-hero #worddeck { opacity: 0 !important; pointer-events: none !important; transition: opacity 0.3s ease; }
}
/* snap departing phase copy out instantly — kills double-exposure overlap between phases */
#hero .phase-exit { transition: opacity 0.09s ease, transform 0.09s ease !important; }

/* ===== HERO PHASE 5 — In-page exercises ===== */

/* hero-copy-p5 enters with the same slide-in pattern as p2/p3 */
#hero .hero-copy-p5 {
  grid-column: 1; grid-row: 1;
  align-self: center; min-width: 0;
  opacity: 0; transform: translateY(44px); pointer-events: none;
  transition: opacity var(--dur-4) ease 0.28s, transform 0.72s var(--ease-out) 0.18s;
}
body.hero-p5 #hero .hero-copy-p5 { opacity: 1; transform: none; pointer-events: auto; }
/* the Simplify scroll cue is mobile-only (lantern-hero-mobile.css switches it
   on); display:none because it is the one in-flow child of .page */
#hero .browser .hh-sbar { display: none; }

/* ex-page: absolutely positioned by default, shown in P5 */
#hero .ex-page {
  position: absolute; top: 0; left: 0; right: 0;
  padding: 26px 32px;
  opacity: 0; pointer-events: none;
  /* leaving Practice the exercises lift + fade; entry only fades (the hero-p5
     rule omits transform from its transition) */
  transform: translateY(-26px);
  transition: opacity 0.3s ease, transform 0.42s cubic-bezier(.5,0,.85,.3), padding-right 0.45s cubic-bezier(.34,.1,.64,1);
}
body.hero-p5 #hero .ex-page {
  opacity: 1; pointer-events: auto;
  transform: none;
  transition: opacity 0.34s ease;
}

/* HUD (inq-hud reused from lantern-v3.css) — hidden until P5 */
#hero .hx-hud { display: none; }
body.hero-p5 #hero .hx-hud { display: block; }

/* menu dropdowns inside the browser — open upward so they don't overflow the frame */
#hero .ex-page .inqgap .menu {
  top: auto; bottom: calc(100% + 7px);
  min-width: 98px; border-radius: var(--r-sm);
}
#hero .ex-page .inqgap .menu button { font-size: var(--fs-eyebrow); padding: 5px 10px; border-radius: var(--r-sm); }
/* the first gap (phenomenon, on the text's 2nd line) is near the top — its
   menu opens downward, or the photo header would cover it */
#hero .ex-page .gap-first .menu { top: calc(100% + 7px); bottom: auto; }
/* Oops! bubble base (the mobile block has its own copy) */
.ex-bubble {
  position: absolute; bottom: calc(100% + 8px); left: 50%;
  z-index: 30; white-space: nowrap;
  font-family: var(--sans, 'General Sans', sans-serif);
  font-weight: 700; font-size: var(--fs-sm); letter-spacing: .01em;
  background: #fff; color: #c43c3c;
  border: 2px solid var(--ink); border-radius: var(--r-md);
  padding: 6px 11px;
  box-shadow: 3px 3px 0 rgba(var(--ink-rgb),.85);   /* deliberately off-tier: hard-offset sticker shadow pairing with the 2px ink border */
  transform: translateX(-50%) scale(.5) rotate(-4deg);
  opacity: 0;
  transition: transform .22s cubic-bezier(.2,1.6,.35,1), opacity var(--dur-1) ease;
  pointer-events: none;
}
.ex-bubble::after {
  content: ""; position: absolute; bottom: -6px; left: 50%;
  width: 9px; height: 9px; transform: translateX(-50%) rotate(45deg);
  background: #fff; border-right: 2px solid var(--ink); border-bottom: 2px solid var(--ink);
}
.ex-bubble.show { transform: translateX(-50%) scale(1) rotate(-4deg); opacity: 1; }
/* hero exercise: menu opens upward, so flip bubble below the gap */
#hero .ex-page .inqgap .ex-bubble { bottom: auto; top: calc(100% + 8px); }
#hero .ex-page .inqgap .ex-bubble::after { bottom: auto; top: -6px; border-right: none; border-bottom: none; border-left: 2px solid var(--ink); border-top: 2px solid var(--ink); }
/* article-choice exercise: plain prose until activated, then a [ ] gap with
   choice pills flying in */
.art-gap { position: relative; }
.art-choices { display: none; }
.art-gap.art-live .art-rest { display: none; }
.art-gap.art-live .art-choices { display: inline-flex; align-items: baseline; gap: 1px; vertical-align: -1px; margin: 0 1px; }
/* the [ ] frame that marks the slot as a fill-in */
.art-br { color: rgba(var(--ink-rgb),.34); font-weight: 600; }
.art-gap.art-live .art-br { animation: artBr .34s ease both; }
@keyframes artBr { from { opacity: 0; } to { opacity: 1; } }
.art-pill { display: inline-block; padding: 2px 6px; border-radius: var(--r-pill); border: 1.5px solid transparent; background: transparent; font-size: var(--fs-sm); font-family: inherit; font-weight: 500; color: var(--ink); cursor: pointer; transition: background .14s, color .14s, border-color .14s; line-height: 1.5; }
/* each pill flies up into the gap, staggered */
.art-gap.art-live .art-pill { animation: artPop .42s cubic-bezier(.2,1.5,.4,1) both; }
.art-gap.art-live .art-pill:nth-of-type(1) { animation-delay: .06s; }
.art-gap.art-live .art-pill:nth-of-type(2) { animation-delay: .15s; }
.art-gap.art-live .art-pill:nth-of-type(3) { animation-delay: .24s; }
@keyframes artPop { from { opacity: 0; transform: translateY(7px) scale(.6); } to { opacity: 1; transform: none; } }
.art-pill:hover, .art-pill.hover { background: rgba(var(--ink-rgb),.09); border-color: rgba(var(--ink-rgb),.3); }
.art-pill.wrong { border-color: #c43c3c; color: #c43c3c; }
.art-pill.chosen { background: var(--green, #2f9e5f); color: #fff; border-color: var(--green, #2f9e5f); pointer-events: none; }
.art-gap.done .art-pill:not(.chosen) { opacity: .3; pointer-events: none; }
.art-sep { color: rgba(var(--ink-rgb),.22); font-size: var(--fs-micro); pointer-events: none; align-self: center; margin: 0 -1px; }
@media (prefers-reduced-motion: reduce) {
  .art-gap.art-live .art-pill, .art-gap.art-live .art-br { animation: none; opacity: 1; transform: none; }
}

/* ===== CTA CHARGE — the six features wire into the install button =====
   Cards + wires live in .cta-dock, built by lantern-cta-charge.js.
   z:-1 keeps them under the headline/button but over the page background. */
.cta-dock { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
/* the six feature cards each orbit a tiny ellipse (--ax/--ay, --fd, --fdelay)
   around their -50%,-50% centring; the wires re-glue every frame */
@keyframes dkFloat {
  0%   { transform: translate(calc(-50% + var(--ax,5px)), calc(-50% + var(--ay,5px))); }
  25%  { transform: translate(calc(-50% - var(--ay,5px)), calc(-50% + var(--ax,5px))); }
  50%  { transform: translate(calc(-50% - var(--ax,5px)), calc(-50% - var(--ay,5px))); }
  75%  { transform: translate(calc(-50% + var(--ay,5px)), calc(-50% - var(--ax,5px))); }
  100% { transform: translate(calc(-50% + var(--ax,5px)), calc(-50% + var(--ay,5px))); }
}
#ev-close .dk-card { animation: dkFloat var(--fd, 8s) ease-in-out var(--fdelay, 0s) infinite; will-change: transform; }
@media (prefers-reduced-motion: reduce) { #ev-close .dk-card { animation: none; } }
/* at rest the cards recede so the headline + CTA own the focus */
#ev-close .dk-card { opacity: .82; filter: saturate(.85); }
/* the heat ramp: JS steps background-color ink → amber per bead; the linear
   transition blurs the steps. Outranks the base .d1-install in lantern-v3.css. */
#ev-close .d1-install { transition: transform var(--dur-2) var(--ease-soft), box-shadow var(--dur-2) ease, background-color .65s linear; }
/* deliberately off-tier: an amber glow, the visible heat of the fully-charged button — not a lift */
.d1-install.blazing { box-shadow: 0 22px 48px -18px rgba(var(--amber-rgb),.7), 0 3px 9px -4px rgba(var(--ink-rgb),.3); }
/* on the fully amber pill the arrow goes white to stay legible */
.d1-install.blazing .d1-arrow { color: #fff; }
/* each bead continues inside the pill as a glowing trace, clipped to it */
.d1-warm { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; pointer-events: none; z-index: var(--z-base); }
.d1-install > span:not(.d1-warm) { position: relative; z-index: 2; }
.d1-touch { position: absolute; width: 64px; height: 64px; margin: -32px 0 0 -32px; border-radius: var(--r-circle);
  background: radial-gradient(circle, rgba(255,186,84,.95), rgba(var(--amber-rgb),.4) 50%, transparent 72%);
  --dx: 0px; --dy: 0px;
  animation: warm-touch var(--dur-4) ease-out forwards; }
@keyframes warm-touch { 0% { opacity: .95; transform: scale(.4) translate(0,0); } 100% { opacity: 0; transform: scale(1.05) translate(var(--dx), var(--dy)); } }
@media (max-width: 979px) { .cta-dock { display: none; } }
/* docked entry: when the finale's flip-clones deliver the cards, the real dock
   cards must appear INSTANTLY where the clones land — no fade/slide */
.dk-card.snap .dk-in { transition: none; opacity: 1; transform: none; }
/* ── finale → CTA flip transition: each article card flies to its dock slot and
   flips to reveal the feature it powers (lantern-everywhere.js builds these) ── */
.flip-clone { position: fixed; left: 0; top: 0; z-index: 1200; pointer-events: none; perspective: 1300px; will-change: transform; }
.fc-rot { position: relative; transform-style: preserve-3d; }
.fc-front, .fc-back { position: absolute; left: 0; top: 0; transform: translate(-50%, -50%);
  backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.fc-back { transform: translate(-50%, -50%) rotateY(180deg); }
.fc-front .pg { margin: 0; }
.fc-back .dk-card { position: relative !important; left: auto !important; top: auto !important; transform: none !important; animation: none !important; }
/* the desktop flip stays desktop-only; the mobile flip opts in with .m-flip */
@media (max-width: 979px) { .flip-clone:not(.m-flip) { display: none; } }
/* mobile flip clones live on <body>, outside the compact `#ev-close .dk-*`
   mobile rules — this mirrors them so the clone lands at the real card's size.
   Keep in sync with those rules (lantern-hero-mobile.css). */
.m-flip .dk-in   { padding: 7px 8px 8px; }
.m-flip .dk-top  { margin-bottom: 4px; }
.m-flip .dk-ic   { width: 26px; height: 26px; border-radius: var(--r-sm); }
.m-flip .dk-prev { display: flex; font-size: 9px; line-height: 1.3; min-height: 0; padding: 5px 6px; gap: 3px; overflow: hidden; }
.m-flip .dk-prev > * { max-width: 100%; min-width: 0; }
.m-flip .dkw  { flex-wrap: wrap; font-size: 9px; padding: 2px 5px; gap: 3px 5px; }
.m-flip .dkw i { font-size: 8px; }
.m-flip .dktr { flex-wrap: wrap; font-size: 9px; gap: 3px 5px; }
.m-flip .dktr .s { flex-basis: 100%; }
.m-flip .dkcz, .m-flip .dksm, .m-flip .dkim { font-size: 9px; line-height: 1.4; }
.m-flip .dkw b, .m-flip .dkok, .m-flip .dktr .t,
.m-flip .dkcz .gap, .m-flip .dksm b, .m-flip .dkim b { font-size: 10.5px; line-height: 1.25; }
.m-flip .dkcz .gap { padding: 0 4px; }
.m-flip .dksm { row-gap: 2px; column-gap: 4px; align-items: baseline; }
.m-flip .dksm s { font-size: 7.5px; }
.m-flip .dksm b { flex-basis: 100%; }
/* Save's A2 badge in the preview's top-right corner (only Save has a .cefr-b) */
.m-flip .dk-prev { position: relative; }
.m-flip .dkw .cefr-b { position: absolute; top: 4px; right: 5px; font-size: 7px; padding: 1px 3px; border-radius: 3px; }
/* ═══════════ ONE-SCREEN MODEL ═══════════
   Everywhere + CTA are NOT scroll sections — they are phase overlays of the one
   pinned hero screen. No scrolling between screens: the browser window morphs
   through the hero phases → splits into the six pages (ph-ev) → the pages dock
   into the install button (ph-cta). Driven by the hero phase engine. */
#finale, #ev-close { position: fixed; inset: 0; z-index: var(--z-sticky); opacity: 0; pointer-events: none; transition: opacity .55s ease; }
body.ph-ev  #finale   { opacity: 1; pointer-events: auto; }
body.ph-cta #ev-close { opacity: 1; pointer-events: auto; z-index: 50; }
body.ph-cta #finale   { opacity: 0; pointer-events: none; }
/* the hero bows out behind the overlays once we leave its phases.
   !important: lantern-v3.js's scroll loop writes #hero opacity inline every frame,
   so a plain rule would lose to it and the hero would never hide. */
body.ph-ev #hero, body.ph-cta #hero { opacity: 0 !important; pointer-events: none; transition: opacity .55s ease; }
/* Practice → Everywhere: the window glides to centre (toEverywhere writes the
   translate inline), squared, bob frozen, copy out. Placed AFTER the hero-pN
   transforms so it wins the !important tie. */
body.ev-centering #hero .floatwrap { animation-play-state: paused; }
body.ev-centering #hero .browser {
  transform: perspective(1300px) rotateY(0deg) rotate(0deg) !important;
  transition: transform 0.55s var(--ease-out) !important;
}
body.ev-centering #hero .hero-copy-p5 {
  opacity: 0 !important;
  transform: translateX(-34px) !important;
  transition: opacity 0.38s ease, transform 0.5s var(--ease-out) !important;
}
/* MY VOCAB glides off right on the wall and Install, and back on return. The
   .at-hero.vocab-on variants out-specify the rule that forces it visible. */
body.ph-ev #worddeck,
body.ph-ev.at-hero.vocab-on #worddeck,
body.ph-cta #worddeck,
body.ph-cta.at-hero.vocab-on #worddeck {
  opacity: 0 !important;
  transform: translateX(150%) !important;
  pointer-events: none !important;
  transition: transform .55s var(--ease-out), opacity .45s ease;
}
/* the scroll gate nudges the cue: one bounce + amber, over the breathing bob */
.ev-cue.nudge { animation: evCueBreathe 2.6s ease-in-out infinite, cueNudge .52s cubic-bezier(.3,.9,.3,1); color: var(--amber-deep); }
@keyframes cueNudge { 0%,100% { transform: translateY(0); } 35% { transform: translateY(5px); } 70% { transform: translateY(0); } }
/* the final CTA takes the shared --cta-h geometry like every other CTA */
#ev-close .d1-install { font-size: var(--fs-read); padding: 0 var(--cta-px) 0 19px; gap: 12px; }
#ev-close .d1-install .d1-chrome { width: 26px; height: 26px; }
/* desktop Install screen: the CTA is its one action — 20% larger, and the step
   name under it goes */
@media (min-width: 921px) {
  #ev-close .d1-install { min-height: calc(var(--cta-h) * 1.2); font-size: calc(var(--fs-read) * 1.2);
                          padding: 0 calc(var(--cta-px) * 1.2) 0 23px; gap: 14px; }
  #ev-close .d1-install .d1-chrome { width: 31px; height: 31px; }
  #ev-close .d1-install .d1-arrow svg { width: 1.2em; height: 1.2em; }
  body.ph-cta #d-deck { display: none; }
}
body.hero-p5 #hero .hx-hud { position: absolute; bottom: 0; left: 0; right: 0; z-index: 2; }

/* desktop-only line break in the Ukrainian subhead (lantern-hero-ring-layout.css) */
#hero .hsub-brk { display: none; }
