/* =====================================================================
   MALHAR 2026 — text-fx.css
   Vanilla, dependency-free text-animation kit (ReactBits-inspired),
   themed to the gilded "Iridescence" palette from site.css.
   Loaded by the static content pages (about / conclave / workforce / contact).
   Driven by [data-fx="..."] attributes; logic lives in text-fx.js.
   ===================================================================== */

/* Anti-FOUC: hide the effects that clear / replace / fade their content until
   the engine has wired them, so the raw text never flashes on page load. Gated
   by the `fx-armed` class (added synchronously in <head>) and auto-released
   after a safety timeout, so text still appears even if the script fails. */
html.fx-armed [data-fx="split"],
html.fx-armed [data-fx="blur"],
html.fx-armed [data-fx="shuffle"],
html.fx-armed [data-fx="decrypt"],
html.fx-armed [data-fx="type"],
html.fx-armed [data-fx="rotate"],
html.fx-armed [data-fx="focus"],
html.fx-armed [data-fx="circular"],
html.fx-armed [data-fx="curved"],
html.fx-armed [data-fx="count"],
html.fx-armed [data-fx="scroll-reveal"],
html.fx-armed [data-fx="scroll-float"],
html.fx-armed [data-fx="scroll-velocity"] { opacity: 0; }

/* Split units the engine injects. Kept inline-block so transforms apply. */
.fx-char,
.fx-word {
  display: inline-block;
  white-space: pre;
  will-change: transform, opacity, filter;
  backface-visibility: hidden;
}
.fx-word { white-space: normal; }

/* Prevent a flash before JS wires reveal effects (only hide the ones that fade in). */
.fx-arm { opacity: 0; }

/* ── Shiny Text ─────────────────────────────────────────────────────── */
.fx-shiny {
  background: linear-gradient(110deg,
      var(--paper-dim) 30%, var(--gold-hi) 48%, #fff 50%, var(--gold-hi) 52%, var(--paper-dim) 70%);
  background-size: 240% 100%;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  animation: fx-shiny-move 5s linear infinite;
}
@keyframes fx-shiny-move { from { background-position: 190% 0; } to { background-position: -90% 0; } }

/* ── Gradient Text (iridescent, on-theme) ───────────────────────────── */
.fx-gradient {
  background: linear-gradient(90deg,
      var(--gold-hi), var(--gold), var(--pink), #7fd4ff, var(--gold-hi));
  background-size: 300% 100%;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  animation: fx-grad 9s linear infinite;
}
@keyframes fx-grad { from { background-position: 0 0; } to { background-position: 300% 0; } }

/* ── Glitch Text ────────────────────────────────────────────────────── */
.fx-glitch { position: relative; display: inline-block; }
.fx-glitch::before,
.fx-glitch::after {
  content: attr(data-text);
  position: absolute;
  left: 0; top: 0;
  width: 100%;
  overflow: hidden;
  pointer-events: none;
}
.fx-glitch::before { color: var(--pink); z-index: -1; animation: fx-glitch-a 2.6s infinite steps(2, end); }
.fx-glitch::after  { color: #7fd4ff;    z-index: -2; animation: fx-glitch-b 3.4s infinite steps(2, end); }
@keyframes fx-glitch-a {
  0%, 92%, 100% { transform: translate(0, 0); clip-path: inset(0 0 0 0); }
  93% { transform: translate(-2px, -1px); clip-path: inset(20% 0 55% 0); }
  96% { transform: translate(2px, 1px);   clip-path: inset(60% 0 12% 0); }
}
@keyframes fx-glitch-b {
  0%, 90%, 100% { transform: translate(0, 0); clip-path: inset(0 0 0 0); }
  91% { transform: translate(2px, 1px);   clip-path: inset(70% 0 8% 0); }
  95% { transform: translate(-2px, -1px); clip-path: inset(10% 0 70% 0); }
}

/* ── Rotating Text ──────────────────────────────────────────────────── */
.fx-rotate { display: inline-grid; vertical-align: bottom; overflow: hidden; }
.fx-rotate > span {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(0.9em) rotateX(-40deg);
  transition: opacity .5s ease, transform .5s cubic-bezier(.2,.7,.2,1);
}
.fx-rotate > span.is-in  { opacity: 1; transform: translateY(0) rotateX(0); }
.fx-rotate > span.is-out { opacity: 0; transform: translateY(-0.9em) rotateX(40deg); }

/* ── True Focus ─────────────────────────────────────────────────────── */
.fx-focus { display: inline-flex; flex-wrap: wrap; gap: 0.3em; position: relative; }
.fx-focus .fx-focus-word { filter: blur(5px); opacity: .55; transition: filter .5s ease, opacity .5s ease; }
.fx-focus .fx-focus-word.is-focus { filter: blur(0); opacity: 1; }
.fx-focus-frame {
  position: absolute; top: 0; left: 0;
  border: 1px solid var(--gold-hi);
  box-shadow: 0 0 14px var(--gold-glow);
  pointer-events: none;
  opacity: 0;
  transition: all .45s cubic-bezier(.3,.7,.2,1);
  border-radius: 3px;
}
.fx-focus-frame.on { opacity: 1; }
.fx-focus-frame::before, .fx-focus-frame::after,
.fx-focus-frame > i::before, .fx-focus-frame > i::after {
  content: ''; position: absolute; width: 9px; height: 9px; border: 2px solid var(--gold-hi);
}
.fx-focus-frame::before { top: -2px; left: -2px; border-right: 0; border-bottom: 0; }
.fx-focus-frame::after  { top: -2px; right: -2px; border-left: 0; border-bottom: 0; }
.fx-focus-frame > i::before { bottom: -2px; left: -2px; border-right: 0; border-top: 0; }
.fx-focus-frame > i::after  { bottom: -2px; right: -2px; border-left: 0; border-top: 0; }

/* ── Text Type / caret ──────────────────────────────────────────────── */
.fx-caret {
  display: inline-block;
  width: 0.06em; height: 1em;
  margin-left: 0.06em;
  background: var(--gold-hi);
  transform: translateY(0.12em);
  animation: fx-blink 1s steps(1) infinite;
}
@keyframes fx-blink { 50% { opacity: 0; } }

/* ── Circular Text ──────────────────────────────────────────────────── */
.fx-circular { position: relative; display: inline-block; }
.fx-circular.spin { animation: fx-spin 16s linear infinite; }
@keyframes fx-spin { to { transform: rotate(360deg); } }
.fx-circular .fx-circular-char {
  position: absolute; left: 50%; top: 50%;
  transform-origin: 0 0;
  color: var(--gold-hi);
}

/* ── Curved Loop ────────────────────────────────────────────────────── */
.fx-curved { width: 100%; display: block; overflow: visible; }
.fx-curved text { fill: var(--gold-hi); font-family: 'Cinzel', serif; text-transform: uppercase; }

/* ── Scramble / Decrypt (leftover styling for the "unresolved" chars) ── */
.fx-scrambling { color: var(--gold); }

/* ── Text Cursor (per-character trail) ──────────────────────────────── */
.fx-textcursor-dot {
  position: fixed; pointer-events: none; z-index: 9998;
  font-family: 'Cinzel Decorative', serif; color: var(--gold-hi);
  text-shadow: 0 0 10px var(--gold-glow); will-change: transform, opacity;
}

/* ── ASCII / Fuzzy canvases ─────────────────────────────────────────── */
.fx-canvas { display: inline-block; vertical-align: middle; }

/* ── Falling Text ───────────────────────────────────────────────────── */
.fx-falling { position: relative; display: inline-block; }
.fx-falling .fx-char { position: relative; }

/* ── Reduced motion: stop the loud, continuous stuff ────────────────── */
@media (prefers-reduced-motion: reduce) {
  .fx-shiny, .fx-gradient { animation: none; }
  .fx-glitch::before, .fx-glitch::after { animation: none; opacity: 0; }
  .fx-circular.spin { animation: none; }
  .fx-arm { opacity: 1 !important; }
}
