/* ============================================================================
   WELL RUN · SIGNAL SYSTEM — SIGNAL TYPE
   The site-wide text-entrance library: one base (.wr-type) + one effect chosen
   with data-type-fx="…". Engine (Signal Type · animations.js sibling) splits the
   text into words / characters / lines, then plays the effect when the element
   scrolls into view. Reuse these — never hand-roll a headline reveal.
   Built on Signal Core tokens in global.css.

   Eleven entrances, four families:
     Fade & lift     · fade-up · rise · blur · skew
     Word & line     · words · lines · flip
     Character       · chars · drop
     Signal broadcast· decode · type · wipe

   SPEED · every duration AND stagger is multiplied by var(--st-speed,1)
   (1 = normal, 2 = half-speed, 0.5 = double-time). Set it globally on an
   ancestor, or per element via the data-type-speed="…" attribute (the engine
   writes it inline). JS-driven effects (decode, type) read the same value.
   ============================================================================ */

/* ── Base ──────────────────────────────────────────────────────────────────
   Until the engine has split an element it stays fully visible (graceful if JS
   is absent). Hidden resting states are gated behind .is-split. */
.wr-type__w,
.wr-type__c,
.wr-type__line-in { display:inline-block; }
.wr-type__line { display:block; }
.wr-type__w-in,
.wr-type__c-in { display:inline-block; will-change:transform, opacity; }
.wr-type__c-in { position:relative; }

/* Per-effect stagger step; --st-i is the part index set by the engine. */
.wr-type { --st-stagger:0ms; }

/* Inline brand-gradient word — mark one word or phrase inside any .wr-type
   headline (<span class="wr-type__grad">signal</span>). The engine keeps it
   intact through the split and animates it as one unit, so the yellow→orange
   brand fill rides the entrance. Pairs with every word and line effect. */
.wr-type__grad {
  background:var(--wr-grad);
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
}

/* While arming a (re)play the engine snaps parts to their hidden state with no
   transition, so the entrance always animates cleanly from the start. */
.wr-type.is-arming,
.wr-type.is-arming .wr-type__w-in,
.wr-type.is-arming .wr-type__c-in,
.wr-type.is-arming .wr-type__line-in,
.wr-type.is-arming .wr-type__wipe-fill { transition:none !important; animation:none !important; }

/* Live typing caret (Type On) — cursor blink, intentionally speed-independent. */
.wr-type__caret {
  display:inline-block; width:0.07em; min-width:2px; height:0.92em;
  margin-left:0.04em; vertical-align:-0.08em; border-radius:2px;
  background:var(--wr-grad);
  animation:stCaret 0.9s steps(1) infinite;
}
@keyframes stCaret { 0%,50%{opacity:1;} 50.01%,100%{opacity:0;} }

/* ════════════════════════════════════════════════════════════════════════════
   GROUP A · FADE & LIFT
   ════════════════════════════════════════════════════════════════════════════ */

/* 01 · Fade Up — whole block fades up. The workhorse. */
.wr-type.is-split[data-type-fx="fade-up"] {
  opacity:0; transform:translateY(26px);
  transition:opacity calc(.7s * var(--st-speed,1)) var(--wr-ease-out),
             transform calc(.8s * var(--st-speed,1)) var(--wr-ease-out);
}
.wr-type.is-in[data-type-fx="fade-up"] { opacity:1; transform:none; }

/* 02 · Rise — words rise out from behind a clip line. */
[data-type-fx="rise"] { --st-stagger:36ms; }
.is-split[data-type-fx="rise"] .wr-type__w {
  overflow:hidden; vertical-align:bottom;
  padding-bottom:0.14em; margin-bottom:-0.14em;
}
.is-split[data-type-fx="rise"] .wr-type__w-in {
  transform:translateY(115%);
  transition:transform calc(.85s * var(--st-speed,1)) var(--wr-ease-out) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1));
}
.is-in[data-type-fx="rise"] .wr-type__w-in { transform:translateY(0); }

/* 03 · Blur Focus — words resolve from soft blur into focus. */
[data-type-fx="blur"] { --st-stagger:50ms; }
.is-split[data-type-fx="blur"] .wr-type__w-in {
  opacity:0; filter:blur(12px); transform:translateY(0.16em);
  transition:opacity calc(.7s * var(--st-speed,1)) var(--wr-ease-out) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1)),
             filter calc(.8s * var(--st-speed,1)) var(--wr-ease-out) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1)),
             transform calc(.8s * var(--st-speed,1)) var(--wr-ease-out) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1));
}
.is-in[data-type-fx="blur"] .wr-type__w-in { opacity:1; filter:blur(0); transform:none; }

/* 04 · Skew Settle — words rise with a skew that settles upright. */
[data-type-fx="skew"] { --st-stagger:42ms; }
.is-split[data-type-fx="skew"] .wr-type__w {
  overflow:hidden; vertical-align:bottom;
  padding-bottom:0.16em; margin-bottom:-0.16em;
}
.is-split[data-type-fx="skew"] .wr-type__w-in {
  transform:translateY(118%) skewY(7deg) rotate(3deg);
  transition:transform calc(.9s * var(--st-speed,1)) cubic-bezier(0.16,1,0.30,1) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1));
}
.is-in[data-type-fx="skew"] .wr-type__w-in { transform:none; }

/* ════════════════════════════════════════════════════════════════════════════
   GROUP B · WORD & LINE
   ════════════════════════════════════════════════════════════════════════════ */

/* 05 · Word Cascade — words fade up one after another. */
[data-type-fx="words"] { --st-stagger:55ms; }
.is-split[data-type-fx="words"] .wr-type__w-in {
  opacity:0; transform:translateY(0.7em);
  transition:opacity calc(.6s * var(--st-speed,1)) var(--wr-ease-out) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1)),
             transform calc(.7s * var(--st-speed,1)) var(--wr-ease-out) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1));
}
.is-in[data-type-fx="words"] .wr-type__w-in { opacity:1; transform:none; }

/* 06 · Line Wipe — each wrapped line is unmasked upward in turn. */
[data-type-fx="lines"] { --st-stagger:90ms; }
.is-split[data-type-fx="lines"] .wr-type__line {
  overflow:hidden; padding-bottom:0.1em; margin-bottom:-0.06em;
}
.is-split[data-type-fx="lines"] .wr-type__line-in {
  transform:translateY(112%);
  transition:transform calc(.9s * var(--st-speed,1)) var(--wr-ease-out) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1));
}
.is-in[data-type-fx="lines"] .wr-type__line-in { transform:none; }

/* 07 · Flip Up — words flip up from flat on a 3D hinge. */
[data-type-fx="flip"] { --st-stagger:50ms; perspective:620px; }
.is-split[data-type-fx="flip"] .wr-type__w-in {
  opacity:0; transform:rotateX(-92deg); transform-origin:50% 0%;
  transition:transform calc(.8s * var(--st-speed,1)) var(--wr-ease-out) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1)),
             opacity calc(.45s * var(--st-speed,1)) linear calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1));
}
.is-in[data-type-fx="flip"] .wr-type__w-in { opacity:1; transform:rotateX(0); }

/* ════════════════════════════════════════════════════════════════════════════
   GROUP C · CHARACTER
   ════════════════════════════════════════════════════════════════════════════ */

/* 08 · Char Cascade — letters fade up left to right. */
[data-type-fx="chars"] { --st-stagger:16ms; }
.is-split[data-type-fx="chars"] .wr-type__c-in {
  opacity:0; transform:translateY(0.35em);
  transition:opacity calc(.5s * var(--st-speed,1)) var(--wr-ease-out) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1)),
             transform calc(.55s * var(--st-speed,1)) var(--wr-ease-out) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1));
}
.is-in[data-type-fx="chars"] .wr-type__c-in { opacity:1; transform:none; }

/* 09 · Letter Drop — letters drop in from above the line. */
[data-type-fx="drop"] { --st-stagger:24ms; }
.is-split[data-type-fx="drop"] .wr-type__c {
  overflow:hidden; vertical-align:top; padding-top:0.12em; margin-top:-0.12em;
}
.is-split[data-type-fx="drop"] .wr-type__c-in {
  transform:translateY(-135%);
  transition:transform calc(.7s * var(--st-speed,1)) cubic-bezier(0.34,1.56,0.5,1) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1));
}
.is-in[data-type-fx="drop"] .wr-type__c-in { transform:translateY(0); }

/* ════════════════════════════════════════════════════════════════════════════
   GROUP D · SIGNAL · BROADCAST
   ════════════════════════════════════════════════════════════════════════════ */

/* 10 · Decode — each letter resolves out of a scramble that locks in place.
   The real glyph holds its box from the first frame (color:transparent), and an
   absolutely-centred overlay (.wr-type__glyph) carries the scramble — so the
   line never reflows or jumps. On lock the overlay fades out as the letter
   fades up to ink. Engine: runDecode in signal-type.js (tick rate scales too). */
.is-split[data-type-fx="decode"] .wr-type__c-in { color:transparent; }
[data-type-fx="decode"] .wr-type__c-in.is-locked {
  color:inherit; transition:color calc(.5s * var(--st-speed,1)) var(--wr-ease-out);
}
[data-type-fx="decode"] .wr-type__glyph {
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  color:var(--wr-orange); pointer-events:none; white-space:pre;
  transition:opacity calc(.26s * var(--st-speed,1)) var(--wr-ease-out);
}

/* 11 · Type On — typed character by character (engine toggles char display). */
.is-split[data-type-fx="type"] { } /* chars stay visible; the engine drives them */

/* 12 · Gradient Wipe — a yellow→orange gradient sweeps the text in, line by line.
   Each wrapped line is a base (dim) + fill (gradient) pair; the fill's clip-path
   opens left→right, staggered per line. Splitter: splitWipe in signal-type.js. */
[data-type-fx="wipe"] { --st-stagger:150ms; display:inline-block; }
[data-type-fx="wipe"] .wr-type__line { position:relative; display:block; }
[data-type-fx="wipe"] .wr-type__wipe-base { color:color-mix(in srgb, currentColor 22%, transparent); }
[data-type-fx="wipe"] .wr-type__wipe-fill {
  position:absolute; left:0; top:0; width:100%;
  background:var(--wr-grad); -webkit-background-clip:text; background-clip:text; color:transparent;
  clip-path:inset(0 100% 0 0);
}
.is-in[data-type-fx="wipe"] .wr-type__wipe-fill {
  animation:stWipe calc(.8s * var(--st-speed,1)) var(--wr-ease-out) calc(var(--st-i) * var(--st-stagger) * var(--st-speed,1)) forwards;
}
@keyframes stWipe { from { clip-path:inset(0 100% 0 0); } to { clip-path:inset(0 0% 0 0); } }

/* ── Reduced motion — show final state, no movement ───────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .wr-type, .wr-type * { transition:none !important; animation:none !important; }
  .wr-type.is-split,
  .wr-type.is-split .wr-type__w-in,
  .wr-type.is-split .wr-type__c-in,
  .wr-type.is-split .wr-type__line-in {
    opacity:1 !important; filter:none !important;
    transform:none !important; clip-path:none !important;
  }
  [data-type-fx="decode"] .wr-type__c-in { color:inherit !important; }
  [data-type-fx="decode"] .wr-type__glyph { display:none !important; }
  [data-type-fx="wipe"] .wr-type__wipe-fill { clip-path:inset(0 0 0 0) !important; }
  .wr-type__caret { display:none !important; }
}
