/* ============================================================
   fx-grammar.css — type & entrance grammar
   Split headings (masked word / letter rise), motion tokens,
   button wipes, the zero-JS magnetic spring, drawn rules and the
   group stagger. Loaded after the main <style>; every rule here
   is a CSS transition — fx-grammar.js only sets classes and --d.
   Owns: .sw/.swi, .rv entrance extras, .btn/.pill/.magnetic,
   .nav/.rail/.manifesto transitions, drawn rules, threat-pulse.
   Does NOT change .rv/.in semantics or the ?shot_y hook.
   ============================================================ */

/* ---------- motion tokens ---------- */
:root{
  --t-fast:.22s;
  --t-base:.55s;
  --t-slow:.9s;
  --ease-out-expo:cubic-bezier(.16,1,.3,1);
  --ease-inout:cubic-bezier(.65,0,.35,1);
  --ease-spring:cubic-bezier(.2,1.35,.3,1);
}

/* ---------- split headings: masked baselines ---------- */
/* .sw is the mask; descenders at line-height 1.08 need the padding,
   the negative margin gives the line box its metrics back. */
.sw{display:inline-block;overflow:hidden;vertical-align:top;padding-bottom:.14em;margin-bottom:-.14em}
.swi{display:inline-block;transform:translateY(112%) rotate(1.5deg);transform-origin:0 100%}

/* reveal headings (.rv on the heading, or on a revealing ancestor —
   the annex .sec-head.rv carries the class for its h2) */
h2.split.rv{transform:none;transition:opacity .45s var(--ease-out) var(--d,0s)}
h2.split.rv .swi,
.rv h2.split .swi{
  transition:transform .9s var(--ease-out-expo);
  transition-delay:calc(var(--d,0s) + var(--i,0)*28ms);
}
h2.split.rv.in .swi,
.rv.in h2.split .swi{transform:none}

/* hero: letters rise once the loader has gone */
.hero-copy h1 .swi{transition:transform .9s var(--ease-out-expo) calc(120ms + var(--i,0)*40ms)}
html.gh-loaded .hero-copy h1 .swi{transform:none}
/* each .sw seam is a soft-wrap opportunity: without this the wordmark
   breaks mid-word (320px, and again past ~1700px) where the plain word
   would only overrun into the padding */
.hero-copy h1.split{white-space:nowrap}
html.js .hero-copy .eyebrow::before{width:0;transition:width .8s var(--ease-out-expo) .5s}
html.gh-loaded .hero-copy .eyebrow::before{width:26px}

/* beats: scrubbed by --wp (the beat window weight), no transitions.
   will-change only on these ~20 spans, never on the other ~200. */
.beat h2 .swi{
  will-change:transform;
  --k:clamp(0, calc((var(--wp,0) - var(--i,0)*.06)*1.6), 1);
  transform:translateY(calc((1 - var(--k))*112%)) rotate(calc((1 - var(--k))*1.5deg));
}
html.no-gl .beat h2 .swi{transform:none}

/* ---------- entrances ---------- */
/* :not(.in) is required — .card.rv alone would out-cascade .rv.in{transform:none} */
.card.rv:not(.in){transform:translateY(34px) scale(.985)}

/* eyebrow rule draws in after its row arrives */
.eyebrow.rv::before{width:0;transition:width .7s var(--ease-out-expo) calc(var(--d,0s) + .1s)}
.eyebrow.rv.in::before{width:26px}

/* ---------- drawn rules ----------
   Borders keep their box metrics: only the colour goes transparent and a
   1px gradient paints into the border area, growing from the left. */
.spec-row.rv,.client.rv,.prog.rv,.hud-note.rv{
  background-image:linear-gradient(var(--border),var(--border));
  background-repeat:no-repeat;
  background-origin:border-box;
  background-size:0% 1px;
  transition:opacity .9s var(--ease-out) var(--d,0s),
             transform .9s var(--ease-out) var(--d,0s),
             background-size .9s var(--ease-draw) var(--d,0s);
}
.spec-row.rv,.client.rv,.hud-note.rv{border-top-color:transparent;background-position:left top}
/* .prog carries its rule on the bottom edge (.progs owns the top one) */
.prog.rv{border-bottom-color:transparent;background-position:left bottom}
/* rows that close a list draw both edges */
.spec-row.rv:last-child,.hud-note.rv:last-child{
  border-bottom-color:transparent;
  background-image:linear-gradient(var(--border),var(--border)),linear-gradient(var(--border),var(--border));
  background-position:left top,left bottom;
  background-size:0% 1px,0% 1px;
}
.spec-row.rv.in,.client.rv.in,.prog.rv.in,.hud-note.rv.in{background-size:100% 1px}

/* children of a revealing parent draw on the parent's .in.
   --d is inherited from the parent, so each cascade sits after its block. */
.notfor.rv li{
  border-top-color:transparent;
  background-image:linear-gradient(var(--border),var(--border));
  background-repeat:no-repeat;background-origin:border-box;
  background-position:left top;background-size:0% 1px;
  transition:background-size .9s var(--ease-draw);
}
.notfor.rv li:nth-child(1){transition-delay:calc(var(--d,0s) + .15s)}
.notfor.rv li:nth-child(2){transition-delay:calc(var(--d,0s) + .21s)}
.notfor.rv li:nth-child(3){transition-delay:calc(var(--d,0s) + .27s)}
.notfor.rv li:nth-child(4){transition-delay:calc(var(--d,0s) + .33s)}
.notfor.rv.in li{background-size:100% 1px}

.card.rv ul{
  border-top-color:transparent;
  background-image:linear-gradient(var(--border),var(--border));
  background-repeat:no-repeat;background-origin:border-box;
  background-position:left top;background-size:0% 1px;
  transition:background-size .9s var(--ease-draw) calc(var(--d,0s) + .25s);
}
.card.rv ul li{
  border-bottom-color:transparent;
  background-image:linear-gradient(var(--border),var(--border));
  background-repeat:no-repeat;background-origin:border-box;
  background-position:left bottom;background-size:0% 1px;
  transition:background-size .9s var(--ease-draw);
}
.card.rv ul li:nth-child(1){transition-delay:calc(var(--d,0s) + .31s)}
.card.rv ul li:nth-child(2){transition-delay:calc(var(--d,0s) + .37s)}
.card.rv ul li:nth-child(3){transition-delay:calc(var(--d,0s) + .43s)}
.card.rv.in ul,.card.rv.in ul li{background-size:100% 1px}

.hud-stage.rv .doc-head,.hud-stage.rv .doc-row{
  border-bottom-color:transparent;
  background-image:linear-gradient(var(--border),var(--border));
  background-repeat:no-repeat;background-origin:border-box;
  background-position:left bottom;background-size:0% 1px;
  transition:background-size .9s var(--ease-draw);
}
.hud-stage.rv .doc-row:last-child{background-image:none}   /* it has no bottom border */
.hud-stage.rv .doc > :nth-child(1){transition-delay:calc(var(--d,0s) + .2s)}
.hud-stage.rv .doc > :nth-child(2){transition-delay:calc(var(--d,0s) + .27s)}
.hud-stage.rv .doc > :nth-child(3){transition-delay:calc(var(--d,0s) + .34s)}
.hud-stage.rv .doc > :nth-child(4){transition-delay:calc(var(--d,0s) + .41s)}
.hud-stage.rv .doc > :nth-child(5){transition-delay:calc(var(--d,0s) + .48s)}
.hud-stage.rv .doc > :nth-child(6){transition-delay:calc(var(--d,0s) + .55s)}
.hud-stage.rv .doc > :nth-child(7){transition-delay:calc(var(--d,0s) + .62s)}
.hud-stage.rv.in .doc-head,.hud-stage.rv.in .doc-row{background-size:100% 1px}

/* ---------- buttons: wipe instead of crossfade ----------
   The main sheet's :hover rules use the `background` shorthand, which
   would reset the wipe layer — so hover re-declares every layer. */
.btn-fill,.pill{
  background-color:#fff;
  background-image:linear-gradient(var(--ink),var(--ink));
  background-size:0% 100%;
  background-repeat:no-repeat;
  transition:background-size var(--t-base) var(--ease-out-expo),color var(--t-fast),border-color var(--t-base);
}
.btn-fill:hover,.pill:hover{
  background-color:#fff;
  background-image:linear-gradient(var(--ink),var(--ink));
  background-size:100% 100%;
  background-repeat:no-repeat;
}
.btn-ghost{
  background-image:linear-gradient(var(--ink),var(--ink));
  background-size:0% 100%;
  background-repeat:no-repeat;
  transition:background-size var(--t-base) var(--ease-out-expo),color var(--t-fast) .08s,border-color var(--t-base);
}
.btn-ghost:hover{background-size:100% 100%;color:#101010;border-color:var(--ink)}

/* magnetic spring with zero JS: while hovered transform has no transition
   (instant tracking); on release the after-change style decides the
   transition, so the button springs back with overshoot. */
.magnetic{
  transition-property:background-size,color,border-color,transform;
  transition-duration:var(--t-base),var(--t-fast),var(--t-base),.55s;
  transition-timing-function:var(--ease-out-expo),ease,ease,var(--ease-spring);
}
.btn-ghost.magnetic{transition-delay:0s,.08s,0s,0s}
.magnetic:hover{transition-property:background-size,color,border-color}

/* ---------- chrome ---------- */
.nav{transition:background var(--t-base),border-color var(--t-base)}
.rail .bar i{transition:height .12s linear}       /* smooths the sub-frame stepping of railFill */
.manifesto .w{transition:color .34s var(--ease-inout)}
/* the one red note in the manifesto: an underline that draws under 'yours.' */
.manifesto .w.sig{position:relative}
.manifesto .w.sig::after{
  content:"";position:absolute;left:.02em;right:.02em;bottom:-.02em;height:.05em;
  background:var(--threat);transform:scaleX(0);transform-origin:left;
  transition:transform .6s var(--ease-out-expo) .25s;
}
.manifesto .w.sig.lit::after{transform:scaleX(1)}

/* BUG FIX: referenced by .dgm__pulse and .holo__pin--threat but never declared */
@keyframes threat-pulse{0%,100%{opacity:1}50%{opacity:.45}}

/* ---------- degrade ---------- */
/* reduced motion (html.rm) */html.rm .swi{transform:none!important}
@media print{
  .swi{transform:none!important}
}
