/* ============================================================================
 * splash.css — brand entrance splash (PWA-026, themed in PWA-038)
 *
 * The .splash-stage is a full-viewport overlay that appears on cold boot,
 * plays the brand mark animation, then fades out and is removed by JS.
 *
 * Two animation paths:
 *   1. anime.js timeline drives the rich path (default). Inline styles
 *      are written to elements; nothing in this file animates them.
 *   2. CSS keyframes path activates when JS adds .splash-css-fallback to
 *      the stage — used when anime.js fails to import. Styles below.
 *
 * Reduced motion: .splash-static class shows everything fully visible
 * with no animation. JS adds it instead of choreography.
 *
 * Theme: PWA-038 (2026-05-11) — splash now uses theme tokens so light
 * mode renders correctly. Dark mode: deep-ink background + light text +
 * cyan accent (unchanged from the original). Light mode: light cool-
 * white background + dark navy text + deeper cyan accent. The text-
 * shadow halos around digits use the same background token so they
 * read as "negative space contour" in both themes.
 *
 * Visual rules ported from apps/site/index.html (marketing site hero).
 * ========================================================================== */

/* ---- Stage shell ---- */

.splash-stage {
  position: fixed;
  inset: 0;
  background: var(--bg-deepest);
  z-index: 9999;          /* above the app shell while playing */
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  pointer-events: none;   /* don't intercept touches; ephemeral */
  /* Subtle paper-grain like the marketing site, so the surface isn't
     dead-flat. Light mode gets a darker dot grain (rgba(0,0,0,...));
     dark mode gets the original lighter grain. The opacity is so low
     (0.015 / 0.025) that the difference is barely perceptible — but
     getting the sign right matters for the texture to read as grain
     rather than a uniform tint. */
  background-image:
    radial-gradient(rgba(255,255,255,0.015) 1px, transparent 1px);
  background-size: 3px 3px;
}

:root[data-theme="light"] .splash-stage {
  background-image:
    radial-gradient(rgba(0,0,0,0.025) 1px, transparent 1px);
}

/* ---- Horizon bands (atmospheric layers behind the mark) ---- */

.splash-horizon {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.splash-band {
  position: absolute;
  left: 0; right: 0;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(0, 224, 255, 0.05) 25%,
    rgba(0, 224, 255, 0.10) 50%,
    rgba(0, 224, 255, 0.05) 75%,
    transparent 100%);
  transform-origin: left;
  opacity: 0;            /* anime.js fades them in */
}

.splash-band-1 { top: 24%; height: 1px; }
.splash-band-2 {
  top: 46%; height: 2px;
  background: linear-gradient(90deg, transparent, rgba(0,224,255,0.18) 50%, transparent);
}
.splash-band-3 { top: 62%; height: 1px; }

/* ---- Scan line (single pass) ---- */

.splash-scan {
  position: absolute;
  left: 0; right: 0;
  top: -10%;
  height: 200px;
  background: linear-gradient(180deg,
    transparent 0%,
    rgba(0, 224, 255, 0.06) 40%,
    rgba(0, 224, 255, 0.10) 50%,
    rgba(0, 224, 255, 0.06) 60%,
    transparent 100%);
  pointer-events: none;
  opacity: 0;
}

/* ---- The mark ---- */

.splash-mark-wrap {
  position: relative;
  z-index: 2;
  text-align: center;
}

.splash-mark {
  /* PWA-038: tick-grey was hardcoded #4a5d72. Now references the
     global --text-faint token which has the right value in both
     themes (dim grey-blue in dark; muted slate in light). The local
     name is kept for readability — "tick grey" is what these are
     visually inside this composition. */
  --tick-grey: var(--text-faint);
  --dot-size: 0.10em;
  display: inline-grid;
  grid-template-columns: auto auto;
  grid-template-rows: auto auto;
  column-gap: 0.18em;
  align-items: end;
  /* PWA-038: was #e8f1f7. Token retheme — light mode gets dark navy
     text, dark mode keeps the original off-white. */
  color: var(--text);
  font-family: "Source Serif 4", ui-serif, Georgia, serif;
  font-weight: 700;
  font-size: clamp(120px, 18vw, 220px);
  line-height: 1;
  letter-spacing: -0.16em;
  text-decoration: none;
  font-feature-settings: "lnum", "tnum";
  position: relative;
}

/* Header variant of the mark (PWA-026 morph target).
   Same composition, much smaller. All the em-relative children
   (ticks, label spacing, dot size) scale automatically. The mark
   that morphs out of the splash is THIS one; the splash mark
   merely transforms toward this position and size. */
.splash-mark.splash-mark-header {
  font-size: 32px;
  letter-spacing: -0.10em;
}

/* In header context, ticks are fully visible by default — no
   entrance animation, no opacity-0 starting state. Same for label,
   digits, and dot. The splash sets these to opacity 0 with anime.js;
   the header version overrides back to opacity 1. */
.splash-mark.splash-mark-header .splash-tick,
.splash-mark.splash-mark-header .splash-label,
.splash-mark.splash-mark-header .splash-d-one,
.splash-mark.splash-mark-header .splash-d-eight,
.splash-mark.splash-mark-header .splash-d-three {
  opacity: 1;
  transform: none;
}
.splash-mark.splash-mark-header .splash-d-dot-inner {
  opacity: 1;
  transform: scale(1);
}

/* Vertical ticks column on the left of the mark */
.splash-ticks-v {
  grid-column: 1; grid-row: 1 / 3;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-self: stretch;
  padding: 0;
}

.splash-tick {
  display: block;
  height: 1.5px;
  width: 0.1em;
  background: var(--tick-grey);
  opacity: 0;             /* anime.js / CSS fallback animates in */
  transform: translateX(-8px);
}

.splash-indicator {
  width: 0.18em;
  height: 2px;
  /* PWA-038: cyan accent → token. */
  background: var(--accent);
}

/* Label "UK SED" — small caps mono beside the digits */
.splash-label {
  grid-column: 2; grid-row: 1;
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Consolas, monospace;
  font-weight: 600;
  font-size: 0.13em;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: #6f8499;
  align-self: end;
  margin-bottom: 0.16em;
  text-align: left;
  opacity: 0;
}

/* The digits 1·8·3 plus the cyan dot */
.splash-digits {
  grid-column: 2; grid-row: 2;
  font-feature-settings: "lnum", "tnum";
  margin-bottom: -0.18em;
  text-align: left;
  position: relative;
}

.splash-d-one,
.splash-d-eight,
.splash-d-three {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.18em);
}

/* Halos on the 8 and 3 — same trick as the marketing site, gives the
   digits a bit of weight against the surrounding surface. The halo
   colour MUST match the stage background — it's a contour that
   pushes the digit forward against the negative space. PWA-038:
   tokenised to var(--bg-deepest) so the halo sign flips correctly
   between dark mode (dark halo on dark surface) and light mode
   (light halo on light surface). */
.splash-d-eight {
  text-shadow:
    0 0 0.012em var(--bg-deepest),
    0 0 0.012em var(--bg-deepest),
    0 0 0.012em var(--bg-deepest);
}
.splash-d-three {
  text-shadow:
    0 0 0.024em var(--bg-deepest),
    0 0 0.024em var(--bg-deepest),
    0 0 0.024em var(--bg-deepest),
    0 0 0.024em var(--bg-deepest);
}

/* The cyan punctuation dot — a real child element so anime.js can
   target it (pseudo-elements aren't reachable from JS). The outer
   .splash-d-dot is a zero-width inline-block anchor; .splash-d-dot-inner
   is the actual dot, absolutely positioned. */
.splash-d-dot {
  color: transparent;
  text-indent: -9999px;
  position: relative;
  display: inline-block;
  width: 0;
  margin-left: 0;
  overflow: visible;
  vertical-align: baseline;
}
.splash-d-dot-inner {
  position: absolute;
  left: -0.06em;
  /* PWA-032: when the dot was a ::after pseudo, bottom: 0.115em
     anchored it correctly above the line-box baseline. Now that
     it's a real element inside an inline-block parent, `bottom`
     is relative to the parent's content box, which sits higher in
     the line-box. Setting bottom: 0 puts it flush with the parent's
     own bottom edge — which IS the digit baseline because the
     parent is a zero-width inline-block on the digit row. */
  bottom: 0;
  width: var(--dot-size);
  height: var(--dot-size);
  /* PWA-038: was hardcoded #00e0ff. Token retheme — dark mode keeps
     the original cyan; light mode uses a slightly deeper cyan that
     reads better on a light surface. */
  background: var(--accent);
  border-radius: 50%;
  /* The 1px ring contains the dot against the surrounding text. Same
     surface-matching reasoning as the digit halos above. */
  box-shadow: 0 0 0 0.024em var(--bg-deepest);
  opacity: 0;
  transform: scale(0.2);
  display: block;
}

/* ============================================================================
 * CSS-keyframes fallback path
 *
 * Activated when JS adds .splash-css-fallback to the stage. Used when
 * anime.js import fails for any reason. Same animation, same timing,
 * just no spring micro-overshoot — outBack easing approximates the feel.
 * ========================================================================== */

.splash-stage.splash-css-fallback .splash-band {
  animation: splashBandIn 500ms ease-out forwards;
}
.splash-stage.splash-css-fallback .splash-band-1 { animation-delay:  50ms; }
.splash-stage.splash-css-fallback .splash-band-2 { animation-delay: 130ms; }
.splash-stage.splash-css-fallback .splash-band-3 { animation-delay: 210ms; }

.splash-stage.splash-css-fallback .splash-scan {
  animation: splashScan 900ms ease-in-out 0ms forwards;
}

.splash-stage.splash-css-fallback .splash-tick:not(.splash-indicator) {
  animation: splashTickIn 200ms ease-out forwards;
}
.splash-stage.splash-css-fallback .splash-t1 { animation-delay: 100ms; }
.splash-stage.splash-css-fallback .splash-t2 { animation-delay: 130ms; }
.splash-stage.splash-css-fallback .splash-t3 { animation-delay: 160ms; }
.splash-stage.splash-css-fallback .splash-t4 { animation-delay: 190ms; }
.splash-stage.splash-css-fallback .splash-t6 { animation-delay: 250ms; }
.splash-stage.splash-css-fallback .splash-t7 { animation-delay: 280ms; }
.splash-stage.splash-css-fallback .splash-t8 { animation-delay: 310ms; }
.splash-stage.splash-css-fallback .splash-t9 { animation-delay: 340ms; }

.splash-stage.splash-css-fallback .splash-indicator {
  animation: splashIndicatorIn 600ms cubic-bezier(.2, .8, .3, 1.4) 320ms forwards;
}

.splash-stage.splash-css-fallback .splash-label {
  animation: splashRise 350ms ease-out 380ms forwards;
}

.splash-stage.splash-css-fallback .splash-d-one {
  animation: splashDigitIn 380ms cubic-bezier(.2, .8, .3, 1) 420ms forwards;
}
.splash-stage.splash-css-fallback .splash-d-eight {
  animation: splashDigitIn 380ms cubic-bezier(.2, .8, .3, 1) 480ms forwards;
}
.splash-stage.splash-css-fallback .splash-d-three {
  animation: splashDigitIn 380ms cubic-bezier(.2, .8, .3, 1) 540ms forwards;
}

.splash-stage.splash-css-fallback .splash-d-dot-inner {
  animation: splashDotLand 500ms cubic-bezier(.2, .8, .3, 1.5) 620ms forwards;
}

@keyframes splashBandIn {
  from { opacity: 0; transform: scaleX(0.6); }
  to   { opacity: 1; transform: scaleX(1); }
}

@keyframes splashScan {
  0%   { opacity: 0; transform: translateY(0); }
  15%  { opacity: 0.7; }
  85%  { opacity: 0.7; }
  100% { opacity: 0; transform: translateY(120vh); }
}

@keyframes splashTickIn {
  to { opacity: 1; transform: translateX(0); }
}

@keyframes splashIndicatorIn {
  0%   { opacity: 0; transform: translateX(-12px) scaleX(0.4); }
  60%  { opacity: 1; transform: translateX(2px) scaleX(1.15); }
  100% { opacity: 1; transform: translateX(0) scaleX(1); }
}

@keyframes splashRise {
  to { opacity: 1; transform: translateY(0); }
}

@keyframes splashDigitIn {
  to { opacity: 1; transform: translateY(0); }
}

@keyframes splashDotLand {
  0%   { opacity: 0; transform: scale(0.2); }
  60%  { opacity: 1; transform: scale(1.25); }
  100% { opacity: 1; transform: scale(1); }
}

/* ============================================================================
 * Reduced motion / static display
 * ========================================================================== */

.splash-stage.splash-static .splash-band,
.splash-stage.splash-static .splash-scan,
.splash-stage.splash-static .splash-tick,
.splash-stage.splash-static .splash-label,
.splash-stage.splash-static .splash-d-one,
.splash-stage.splash-static .splash-d-eight,
.splash-stage.splash-static .splash-d-three {
  opacity: 1;
  transform: none;
  animation: none !important;
}

.splash-stage.splash-static .splash-d-dot-inner {
  opacity: 1;
  transform: scale(1);
  animation: none !important;
}

.splash-stage.splash-static .splash-scan { display: none; }

