/* ============================================================================
   motion.css — Oyang Archive motion foundation
   Styles for the ink-veil view-transition overlay, the upgraded (tapered,
   brush-stroke) reading-progress bar, and the .oa-motion gate that
   motion-core.js adds to <html> once GSAP/ScrollTrigger/Lenis are live and
   the visitor has not asked for reduced motion. Everything here degrades to
   nothing when .oa-motion is absent: no-JS and reduced-motion visitors keep
   the plain instant view-switch and the flat vermilion progress bar that
   already existed in index.html/script.js.
   Theme-aware via [data-theme="dark"], matching theme.css's token names.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   1. Reading progress — tapered brush-stroke trailing edge
   Only applied once .oa-motion is on <html>; otherwise the original flat
   inline background (#9e2b25 / dark override in theme.css) stands untouched.
   --------------------------------------------------------------------------- */
html.oa-motion #readingProgress {
  background: linear-gradient(90deg,
    rgba(158, 43, 37, 0)    0%,
    rgba(158, 43, 37, .5)   12%,
    #9e2b25 46%,
    #b23a33 100%) !important;
  box-shadow:
    0 0 10px 1px rgba(158, 43, 37, .30),
    0 0 3px rgba(158, 43, 37, .55);
  border-radius: 0 2px 2px 0;
}
html[data-theme="dark"].oa-motion #readingProgress {
  background: linear-gradient(90deg,
    rgba(228, 106, 96, 0)   0%,
    rgba(228, 106, 96, .45) 12%,
    #e46a60 46%,
    #d1483f 100%) !important;
  box-shadow:
    0 0 12px 1px rgba(228, 106, 96, .40),
    0 0 4px rgba(228, 106, 96, .65);
}

/* ---------------------------------------------------------------------------
   2. Ink-veil view-transition overlay
   Created and animated entirely by motion-core.js (#oaVeil, appended to
   <body>); absent for no-JS visitors, so it never needs a static fallback.
   Paper-colour panel with a soft blurred ink edge + a thin vermilion seal
   line at the wiping edge. transform-origin: bottom + scaleY lets the top
   edge retreat downward, revealing the new view from the top down.
   --------------------------------------------------------------------------- */
#oaVeil {
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  background: var(--color-bg, #f6f5f2);
  opacity: 0;
  transform: scaleY(0);
  transform-origin: bottom;
  will-change: transform, opacity;
}
#oaVeil::before {
  /* soft ink bleed just ahead of the retreating (top) edge */
  content: "";
  position: absolute;
  left: 0; right: 0;
  top: -56px;
  height: 56px;
  background: linear-gradient(180deg, rgba(246, 245, 242, 0) 0%, var(--color-bg, #f6f5f2) 100%);
  filter: blur(11px);
}
#oaVeil::after {
  /* thin vermilion seal-ink line riding the wiping edge */
  content: "";
  position: absolute;
  left: 0; right: 0;
  top: 0;
  height: 2px;
  background: #9e2b25;
  box-shadow: 0 0 10px 2px rgba(158, 43, 37, .5);
  opacity: .75;
}
html[data-theme="dark"] #oaVeil {
  background: var(--d-bg, #17130f);
}
html[data-theme="dark"] #oaVeil::before {
  background: linear-gradient(180deg, rgba(23, 19, 15, 0) 0%, var(--d-bg, #17130f) 100%);
}
html[data-theme="dark"] #oaVeil::after {
  background: #e46a60;
  box-shadow: 0 0 12px 2px rgba(228, 106, 96, .55);
}

/* ---------------------------------------------------------------------------
   3. The home hero's opening — intro gate + striking stage

   The page opens on the mark alone. It spins, throws the title out in 漢字,
   turns that into English, and only then does the rest of the hero arrive;
   the nav, the buttons and the free-cue line wait for a scroll (or six
   seconds). Two pieces of CSS make that possible:

   a) `html.oa-intro` — set by the head bootstrap before first paint, so the
      elements motion-hero.js is about to choreograph are already invisible on
      the very first frame. Priming them from JS at the end of <body> would
      let the finished hero paint and then blink out. Released again by
      motion-hero.js (both its success and its bail-out path) and by an 8s
      failsafe timer, so no route through the page can leave content hidden.
      Note the `!important`: the hero is authored with inline styles, and the
      lead paragraph's own `opacity` would otherwise win the cascade.

   b) `.oa-hero-stage` — the medallion + 漢字 layer, sitting absolutely over
      the h1 so the Chinese and the English occupy exactly the same box and
      the conversion between them reads as one surface turning.

      It is keyed on `html.oa-hero-live`, which motion-hero.js adds itself,
      in the same synchronous stretch as (and immediately after) it primes
      the 漢字 to invisible — deliberately NOT on `html.oa-motion`, which
      motion-core.js owns. Those are two separate <script src> tags: keying
      the stage on the first one means any load where motion-core.js succeeds
      and motion-hero.js does not (404, CSP, parse error) shows the un-primed
      Chinese title stacked permanently on top of the English one, and lets
      the browser flash it if it happens to paint between the two files.
      Tying it to the file that actually drives it closes both, and keeps
      no-JS and reduced-motion visitors on the plain finished hero.
   --------------------------------------------------------------------------- */
html.oa-intro [data-hero-watermark],
html.oa-intro [data-hero="home"] [data-hero-eyebrow],
html.oa-intro [data-hero="home"] h1,
html.oa-intro [data-hero="home"] [data-hero-lead],
html.oa-intro [data-hero="home"] [data-hero-ctas],
html.oa-intro [data-hero="home"] .oa-freecue {
  opacity: 0 !important;
}
html.oa-intro [data-site-header] {
  opacity: 0 !important;
  transform: translateY(-100%);
  pointer-events: none;
}
html.oa-intro [data-hero="home"] [data-hero-ctas] {
  pointer-events: none;
}

.oa-hero-stage { display: none; }
html.oa-hero-live .oa-hero-stage {
  display: grid;
  position: absolute;
  inset: 0;
  place-items: center;
  pointer-events: none;
  z-index: 2;
  perspective: 1100px;
}
/* mark and 漢字 share one grid cell: the characters are thrown from exactly
   where the mark is spinning, not from beside it */
.oa-hero-stage > * { grid-area: 1 / 1; }

.oa-hero-han {
  display: grid;
  justify-items: center;
  font-family: 'Noto Serif TC', serif;
  font-weight: 900;
  font-size: clamp(36px, 5.4vw, 70px);
  line-height: 1.1;
  letter-spacing: .14em;
  /* letter-spacing hangs an extra gap off the last glyph; the indent pulls the
     line back so it is optically centred over the English title, not offset */
  text-indent: .14em;
  color: var(--p-t1, #14110f);
  white-space: nowrap;
  /* The stage's own perspective applies to *its* children, i.e. to this block
     (which carries the rotationY of the mark's spin) — not to the lines
     inside it. Without a perspective of its own here the block is a flat
     rendering context, so the 漢字 line turning away in beat 3 would squash
     orthographically while the English line turning in behind it — whose
     wrapper gets perspective:1100px from splitHeadingLines — turns with real
     foreshortening. Matching the value is what makes the two read as one
     surface showing its other face rather than as two unrelated tricks. */
  perspective: 1100px;
}
html[data-theme="dark"] .oa-hero-han { color: var(--d-text, #ece6dc); }
.oa-hero-han > span {
  display: block;
  backface-visibility: hidden;
}

/* the cloned nav medallion, at hero scale. --oa-mark-t / --oa-mark-persp are
   authored in style.css as ratios of --oa-mark-h, and custom properties
   substitute per element, so overriding the height alone rescales the
   medallion's thickness, perspective and corner radius with it. */
.oa-hero-mark { --oa-mark-h: clamp(92px, 12vw, 148px); }

/* ---------------------------------------------------------------------------
   4. Lenis / native-scroll handoff
   motion-core.js adds this class to <html> once Lenis is driving the page,
   so the CSS `scroll-behavior: smooth` set in style.css (html{scroll-behavior
   :smooth}) stops fighting Lenis's own easing on programmatic scrollIntoView
   / scrollTo calls.
   --------------------------------------------------------------------------- */
html.oa-lenis {
  scroll-behavior: auto !important;
}

/* ---------------------------------------------------------------------------
   5. Reduced motion — neutralize everything above
   Belt-and-braces: motion-core.js already refuses to add .oa-motion / build
   the veil / init Lenis when this query matches, so in practice these rules
   are a defensive fallback (e.g. a stale .oa-motion class left on <html> by
   a bfcache restore).
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html.oa-motion #readingProgress {
    background: #9e2b25 !important;
    box-shadow: none;
    border-radius: 0;
  }
  html[data-theme="dark"].oa-motion #readingProgress {
    background: var(--d-accent, #e46a60) !important;
    box-shadow: none;
  }
  #oaVeil,
  #oaVeil::before,
  #oaVeil::after {
    display: none !important;
  }
  html.oa-lenis {
    scroll-behavior: smooth !important;
  }
  /* The head bootstrap already refuses to set .oa-intro under reduced motion,
     and motion-hero.js bails before building the stage. These two are the
     belt-and-braces equivalent of the rules above: a stale class from a
     bfcache restore must never hide the hero or reveal the stage. */
  html.oa-intro [data-hero-watermark],
  html.oa-intro [data-hero="home"] [data-hero-eyebrow],
  html.oa-intro [data-hero="home"] h1,
  html.oa-intro [data-hero="home"] [data-hero-lead],
  html.oa-intro [data-hero="home"] [data-hero-ctas],
  html.oa-intro [data-hero="home"] .oa-freecue,
  html.oa-intro [data-site-header] {
    opacity: 1 !important;
    transform: none;
    pointer-events: auto;
  }
  html.oa-hero-live .oa-hero-stage { display: none; }
}
