/* Ice House: page tokens, loader, HUD and copy. Owned by the core.
   Layer-owned styles live in their own files (css/frost.css, css/crystals.css). */
:root {
  --field: #b9c2cc;
  --snow: #eef3f6;
  --ice: #bfd3df;
  --slate: #24313d;
  --night: #05080c;
  --glow: #8ff6ff;

  /* --ink is rewritten every frame by hud.js: dark slate on the bright legs,
     snow on the night legs, interpolated through the crossfades. */
  --ink: #16212b;
  --ink-soft: color-mix(in oklab, var(--ink) 88%, transparent);
  --ink-faint: color-mix(in oklab, var(--ink) 38%, transparent);
  --hair: color-mix(in oklab, var(--ink) 26%, transparent);
  --halo: rgba(238, 243, 246, 0);      /* soft lift behind text, set per leg */

  --font-hud: "Martian Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  --font-display: "Bodoni Moda", "Didot", "Bodoni 72", Georgia, serif;
  --hud-size: clamp(10.5px, 0.34vw + 6.4px, 12px);
  --gut: clamp(16px, 2.2vw, 34px);
  --ease: cubic-bezier(.2, .7, .1, 1);

  --frost: 0;              /* 0..1, written by fx/frost.js */

  /* engine tokens (the accent replaces the engine's lime focus/selection colour) */
  --sc-accent: #8ff6ff;
  --sc-accent-ink: #05080c;
  --sc-canvas: #b9c2cc;
  --sc-ink: var(--ink);
  --sc-gutter: var(--gut);
  --sc-font-display: var(--font-display);
  --sc-font-text: var(--font-display);
  --sc-font-mono: var(--font-hud);
}

html { scrollbar-width: none; background: var(--field); }
html::-webkit-scrollbar { display: none; }
html.is-loading { overflow: hidden; }
/* the open manifesto owns the wheel: the film behind it must not scroll */
html:has(dialog[open]) { overflow: hidden; }

/* visually hidden, still read by assistive tech */
.sr-only, .beat__title-sr {
  position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}
.nw { white-space: nowrap; }
body {
  margin: 0;
  background: var(--field);
  color: var(--ink);
  font-family: var(--font-display);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
::selection { background: color-mix(in oklab, var(--glow) 45%, transparent); color: var(--night); }

/* ---------------------------------------------------------------- stage */
.world { background: var(--field); }
.gl {
  position: fixed; inset: 0;
  width: 100vw; height: 100vh; height: 100svh;
  display: block;
  z-index: 5;
  pointer-events: none;
  opacity: 0;               /* shown once the first real frame has rendered */
  transition: opacity 600ms var(--ease);
}
.gl.is-live { opacity: 1; }
.copy { z-index: 20; }
.hud-layer { position: fixed; inset: 0; z-index: 40; pointer-events: none; }
/* layer-owned DOM (crystal callouts) belongs to the GL film: gone with it
   (pass 3: after a lost context the callout stayed, clickable, over the DOM film) */
html:not(.gl-on) .hud-layer { display: none; }
.hud-layer > * { pointer-events: auto; }

/* ---------------------------------------------------------------- loader */
.loader {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  background: var(--field);
  color: #16212b;
  font-family: var(--font-hud);
  font-size: var(--hud-size);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: opacity 900ms var(--ease), visibility 0s linear 900ms;
}
.loader.is-done { opacity: 0; visibility: hidden; }
.loader__inner { display: grid; justify-items: center; gap: 1.1em; }
.loader__bar {
  margin: 0;
  font-size: calc(var(--hud-size) * 1.45);
  font-variation-settings: "wdth" 112.5;
  font-weight: 300;
  letter-spacing: 0.32em;
  margin-right: -0.32em;
  white-space: pre;
}
.loader__meta { margin: 0; display: flex; gap: .6em; font-variant-numeric: tabular-nums; color: #3d4b58; }
.loader__sep { opacity: .5; }
.loader__line { margin: 0; color: #3d4b58; font-weight: 300; min-height: 1.4em; }

/* ---------------------------------------------------------------- HUD */
/* One scrim per corner, each in its own tone (hud.js: --scrim-tl/tr/bl/br on
   :root, falling back to the global --scrim). Same plateau shape as before:
   dense behind the text, feathering toward the centre. The vertical plateau is
   the background, the horizontal one a mask, so the two multiply. */
.edge-scrim {
  /* z 15: above the film canvas (5), BELOW the copy (20), the layer HUD (40)
     and the corner HUD (60). Above the copy it veiled every caption's last line */
  position: fixed; z-index: 15; pointer-events: none;
  /* a soft pool from each corner. One eased radial falloff, no plateau: on a
     flat whiteout the old linear plateau edges showed as pale rectangles */
  width: clamp(300px, 42vw, 720px);
  --_s: var(--scrim, transparent);
  background: var(--_s);
  --_m: #000 0%, rgba(0,0,0,.95) 25%, rgba(0,0,0,.82) 42%, rgba(0,0,0,.6) 58%, rgba(0,0,0,.35) 72%, rgba(0,0,0,.14) 86%, transparent 100%;
  transition: opacity 700ms var(--ease);
}
.edge-scrim--tl, .edge-scrim--tr { top: 0; height: clamp(150px, 26vh, 250px); }
.edge-scrim--bl, .edge-scrim--br { bottom: 0; height: clamp(170px, 30vh, 280px); }
.edge-scrim--tl { left: 0; -webkit-mask-image: radial-gradient(ellipse 100% 100% at 0 0, var(--_m)); mask-image: radial-gradient(ellipse 100% 100% at 0 0, var(--_m)); }
.edge-scrim--tr { right: 0; -webkit-mask-image: radial-gradient(ellipse 100% 100% at 100% 0, var(--_m)); mask-image: radial-gradient(ellipse 100% 100% at 100% 0, var(--_m)); }
.edge-scrim--bl { left: 0; -webkit-mask-image: radial-gradient(ellipse 100% 100% at 0 100%, var(--_m)); mask-image: radial-gradient(ellipse 100% 100% at 0 100%, var(--_m)); }
.edge-scrim--br { right: 0; -webkit-mask-image: radial-gradient(ellipse 100% 100% at 100% 100%, var(--_m)); mask-image: radial-gradient(ellipse 100% 100% at 100% 100%, var(--_m)); }
.edge-scrim--tl { --_s: var(--scrim-tl, var(--scrim, transparent)); }
.edge-scrim--tr { --_s: var(--scrim-tr, var(--scrim, transparent)); }
.edge-scrim--bl { --_s: var(--scrim-bl, var(--scrim, transparent)); }
.edge-scrim--br { --_s: var(--scrim-br, var(--scrim, transparent)); }
.is-loading .edge-scrim, .is-intro .edge-scrim { opacity: 0; }

/* Corner ink contract: hud.js sets --ink and --halo inline on each .hud--xx
   element. Every HUD descendant reads them by inheritance; the derived tokens
   are re-derived here (on the corner itself) so they follow the corner's ink,
   not the :root one. Never set --ink inside a corner. */
.hud {
  position: fixed; z-index: 60;
  --ink-soft: color-mix(in oklab, var(--ink) 88%, transparent);
  --ink-faint: color-mix(in oklab, var(--ink) 38%, transparent);
  --hair: color-mix(in oklab, var(--ink) 26%, transparent);
  --ice-halo: 0 0 1.2em var(--halo), 0 0 .3em var(--halo);
  font-family: var(--font-hud);
  font-size: var(--hud-size);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  line-height: 1.45;
  /* arrives after the title and caption at the end of the intro */
  transition: opacity 900ms var(--ease) 300ms;
}
.is-loading .hud, .is-intro .hud { opacity: 0; pointer-events: none; }
.hud--tl { top: var(--gut); left: var(--gut); }
.hud--tr { top: var(--gut); right: var(--gut); }
.hud--bl { bottom: var(--gut); left: var(--gut); }
.hud--br { bottom: var(--gut); right: var(--gut); text-align: right; }

.wordmark { display: grid; gap: .35em; color: inherit; text-decoration: none; }
.wordmark__name {
  font-size: calc(var(--hud-size) * 1.35);
  font-weight: 500;
  font-variation-settings: "wdth" 112.5;
  letter-spacing: 0.34em;
}
.wordmark__sub { color: var(--ink-soft); font-weight: 300; }

.hud-btn {
  appearance: none; border: 0; background: none; padding: .55em 0; margin: -.55em 0;
  font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit;
  display: inline-flex; align-items: center; gap: .7em; cursor: pointer;
}
/* two-colour ring: ink line plus a halo bed, so it survives any backdrop */
.hud-btn:focus-visible, .wordmark:focus-visible {
  outline: 2px solid var(--ink); outline-offset: 6px; border-radius: 2px;
  box-shadow: 0 0 0 10px var(--halo);   /* 2px past the outline, so the ring has a bed on both sides */
}
.hud-btn__dot {
  width: 6px; height: 6px; border: 1px solid currentColor; border-radius: 50%;
  transition: background-color 300ms var(--ease);
}
.hud-btn:hover .hud-btn__dot { background: currentColor; }

.sound__bars { display: inline-flex; align-items: flex-end; gap: 2px; height: 10px; }
.sound__bars i {
  display: block; width: 2px; height: 2px; background: currentColor;
  transition: height 300ms var(--ease);
}
.sound[aria-pressed="true"] .sound__bars i { animation: bar 1.1s var(--ease) infinite alternate; }
.sound[aria-pressed="true"] .sound__bars i:nth-child(2) { animation-delay: -.3s; }
.sound[aria-pressed="true"] .sound__bars i:nth-child(3) { animation-delay: -.7s; }
.sound[aria-pressed="true"] .sound__bars i:nth-child(4) { animation-delay: -.15s; }
.sound[aria-pressed="true"] .sound__bars i:nth-child(5) { animation-delay: -.5s; }
@keyframes bar { from { height: 2px; } to { height: 10px; } }
.sound__label b { font-weight: 500; }

.readout { display: grid; gap: .3em; justify-items: end; }
.readout__row { display: flex; gap: .55em; font-variant-numeric: tabular-nums; }
/* 62% (reviewer F) measured 3.6-3.9:1 on the day legs; 78% clears 4.5 and still reads as secondary */
.readout__of { color: color-mix(in oklab, var(--ink) 86%, transparent); margin-left: -.55em; }
.readout__name { min-width: 9ch; text-align: right; }
.readout__row--soft { color: var(--ink-soft); font-weight: 300; }
#ro-coord::before { content: "· "; }   /* same separator as the callouts */
.rail { display: flex; gap: 5px; list-style: none; margin: .45em 0 0; padding: 0; }
.rail li {
  width: 16px; height: 1px; background: var(--hair);
  position: relative; overflow: hidden;
}
.rail li::after {
  content: ""; position: absolute; inset: 0; background: var(--ink);
  transform-origin: left; transform: scaleX(var(--fill, 0));
  transition: transform 260ms var(--ease);   /* the loop's reset reads as a release, not a blink */
}

/* ---------------------------------------------------------------- copy */
.beat { color: var(--ink); }
.beat__mono {
  margin: 0 0 1.1em;
  font-family: var(--font-hud);
  font-size: var(--hud-size);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--ink);        /* full ink: at 88% the eyebrows measured 3.9-4.4:1 over the milky hero and the lit plain */
  display: flex; gap: .9em; align-items: baseline;
}
.beat__idx { color: var(--ink); font-weight: 500; }
.beat__idx::after { content: ""; display: inline-block; width: 22px; height: 1px; background: var(--hair); margin-left: .9em; vertical-align: middle; }
.beat__line {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.15rem, 0.9vw + 0.85rem, 1.95rem);
  line-height: 1.22;
  letter-spacing: -0.005em;
  max-width: 26ch;
  text-wrap: pretty;
}
.beat__line--lg {
  font-size: clamp(1.75rem, 2.4vw + 0.7rem, 3.5rem);
  line-height: 1.04;
  letter-spacing: -0.018em;
  max-width: 15ch;
}
.beat__credit {
  margin: 1.4em 0 0;
  font-family: var(--font-hud);
  font-size: var(--hud-size);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-weight: 300;
}
.sc-copy.beat { max-width: min(40rem, 70vw); }
.beat--lead  { left: var(--gut); right: auto; top: auto; bottom: calc(var(--gut) + 4.4rem); }
.beat--trail { left: auto; right: var(--gut); top: auto; bottom: calc(var(--gut) + 6.2rem); text-align: right; }
.beat--top   { left: var(--gut); right: auto; bottom: auto; top: calc(var(--gut) + 4.6rem); }
.beat--trail .beat__mono { justify-content: flex-end; }
.beat--trail .beat__line { margin-left: auto; }
/* a pocket of clear air behind the copy: a wide, soft radial bed in the
   leg's own tone (hud.js sets --pocket), so the type reads over stone, snow
   or aurora without a box */
.beat { isolation: isolate; }
.beat::before {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  inset: -48% -14% -40% -10%;   /* tight sideways (no smudge beside the caption), full height so the eyebrow stays on the bed */
  background: radial-gradient(farthest-side, var(--pocket, transparent) 0%, var(--pocket, transparent) 50%, color-mix(in srgb, var(--pocket, transparent) 45%, transparent) 76%, transparent 100%);
  filter: blur(22px);
}
/* soft lift behind text, only as strong as the leg needs (hud.js sets --halo).
   frost.css owns text-shadow on [data-ice] and appends var(--ice-halo), so the
   halo is handed over as a variable, with the plain shadow kept for anything
   that is not frost-marked. */
.beat__line, .beat__mono, .beat__credit {
  --ice-halo: 0 0 1.4em var(--halo), 0 0 .35em var(--halo);
  text-shadow: var(--ice-halo);
}

/* hero: positioned by hand, opacity by hud.js */
.beat--hero {
  position: fixed; z-index: 20;
  left: var(--gut); bottom: calc(var(--gut) + 3.6em);
  width: max-content;
  max-width: min(34rem, 80vw);
  opacity: 0;
  pointer-events: none;
}
/* the hero line breaks by hand (two clauses), so it may run past 26ch */
.beat--hero .beat__line { max-width: none; }

/* ---------------------------------------------------------------- manifesto */
.manifesto {
  border: 0; padding: 0; margin: auto; background: transparent; color: #eef3f6;
  max-width: min(40rem, calc(100vw - 2 * var(--gut)));
  max-height: calc(100svh - 2 * var(--gut));
  overflow: visible;
}
.manifesto::backdrop {
  background: rgba(10, 16, 22, .46);
  backdrop-filter: blur(18px) saturate(.8);
  -webkit-backdrop-filter: blur(18px) saturate(.8);
}
.manifesto[open] { animation: rise 700ms var(--ease) both; }
.manifesto[open]::backdrop { animation: fade 700ms var(--ease) both; }
@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.manifesto__glass {
  position: relative;
  --mpad: clamp(24px, 4vw, 48px);
  padding: var(--mpad);
  /* smoked slate, not pale glass (pass 3: white Bodoni hairlines measured
     ~3.3:1 on the pale glass over the day legs) */
  background: linear-gradient(160deg, rgba(40, 56, 72, .62), rgba(16, 24, 34, .76));
  border: 1px solid rgba(238, 243, 246, .22);
  border-radius: 3px;
  box-shadow: 0 30px 80px -30px rgba(0, 0, 0, .55);
  max-height: calc(100svh - 2 * var(--gut));
  overflow: auto;
}
.manifesto__eyebrow, .manifesto__credits, .manifesto__close {
  font-family: var(--font-hud); font-size: var(--hud-size); letter-spacing: .08em; text-transform: uppercase;
}
.manifesto__eyebrow { margin: 0 0 2em; color: rgba(238, 243, 246, .7); font-weight: 300; }
.manifesto__title {
  margin: 0 0 .8em; font-weight: 400; font-size: clamp(1.9rem, 2.6vw + .8rem, 3.2rem);
  line-height: 1.02; letter-spacing: -0.02em; max-width: 14ch;
}
.manifesto__body p { margin: 0 0 1em; font-size: clamp(1rem, .4vw + .9rem, 1.15rem); line-height: 1.55; max-width: 52ch; color: rgba(238, 243, 246, .9); }
.manifesto__credits {
  margin: 2.2em 0 0; padding-top: 1.6em; border-top: 1px solid rgba(238, 243, 246, .18);
  display: grid; gap: .7em; font-weight: 300;
}
.manifesto__credits div { display: grid; grid-template-columns: 12em 1fr; gap: 1em; }
.manifesto__credits dt { color: rgba(238, 243, 246, .62); }
.manifesto__credits dd { margin: 0; text-transform: none; letter-spacing: .02em; text-wrap: pretty; }
.manifesto__credits a { color: inherit; text-underline-offset: 3px; }
.manifesto__close { position: absolute; top: clamp(16px, 2.6vw, 30px); right: clamp(16px, 2.6vw, 30px); color: #eef3f6; }
.manifesto__close:focus-visible { outline-color: #eef3f6; box-shadow: none; }
.manifesto a:focus-visible {
  outline: 2px solid var(--glow); outline-offset: 3px; border-radius: 2px;
  text-decoration-color: var(--glow);
}

.noscript { position: fixed; inset: auto 0 2rem; text-align: center; font-family: var(--font-hud); }

/* ---------------------------------------------------------------- cursor */
@media (pointer: fine) {
  html.has-cursor, html.has-cursor a, html.has-cursor button { cursor: none; }
  .cursor {
    position: fixed; left: 0; top: 0; z-index: 90; pointer-events: none;
    width: 0; height: 0; color: var(--ink);
    opacity: 0; transition: opacity 300ms var(--ease);
  }
  .cursor.is-on { opacity: 1; }
  .cursor__ring, .cursor__dot { position: absolute; display: block; border-radius: 50%; }
  .cursor__ring {
    width: 26px; height: 26px; left: -13px; top: -13px;
    border: 1px solid currentColor; opacity: .55;
    transition: transform 380ms var(--ease), opacity 380ms var(--ease);
  }
  .cursor__dot { width: 3px; height: 3px; left: -1.5px; top: -1.5px; background: currentColor; }
  .cursor.is-hot .cursor__ring { transform: scale(1.7); opacity: .9; }
  .cursor.is-down .cursor__ring { transform: scale(.8); }
  dialog[open] ~ .cursor { color: #eef3f6; }
}
@media (pointer: coarse) { .cursor { display: none; } }

/* ---------------------------------------------------------------- phones */
@media (max-width: 760px) {
  .hud--br .readout__row--soft { display: none; }
  .wordmark__sub { display: none; }
  .beat__line--lg { font-size: clamp(1.55rem, 6.4vw, 2.2rem); max-width: 16ch; }
  .beat--hero { bottom: calc(var(--gut) + 4.2em); }
  .beat--top { top: calc(var(--gut) + 3.6rem); }
  .sc-copy.beat { max-width: none; }
  .beat--lead, .beat--trail { left: var(--gut); right: var(--gut); bottom: calc(var(--gut) + 4.6rem); text-align: left; }
  .beat--trail .beat__mono { justify-content: flex-start; }
  .beat--trail .beat__line { margin-left: 0; }
  .manifesto__credits div { grid-template-columns: 1fr; gap: .15em; }
}
/* small or short screens: the glass scrolls, so Close must ride along with it */
@media (max-width: 760px), (max-height: 520px) {
  /* a full-width footer that fades the text behind Close (pass 3: a
     translucent box sitting on the last credit line looked broken) */
  .manifesto__foot {
    position: sticky; bottom: calc(-1 * var(--mpad)); z-index: 1;
    display: flex; justify-content: flex-end;
    margin: 1em calc(-1 * var(--mpad)) calc(-1 * var(--mpad));
    padding: 1.8em var(--mpad) var(--mpad);
    background: linear-gradient(to bottom, rgba(16, 24, 34, 0), rgba(16, 24, 34, .92) 48%);
  }
  /* (.manifesto prefix: the touch rule's negative .hud-btn margins pulled
     Close up onto the last credit line) */
  .manifesto .manifesto__close {
    position: static; margin: 0;
    display: flex; width: max-content; padding: 14px 18px;
    background: rgba(22, 32, 42, .78); border: 1px solid rgba(238, 243, 246, .22); border-radius: 2px;
    -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  }
}
/* touch: 44 px-class targets without moving anything visually */
@media (pointer: coarse) {
  .hud-btn { padding-top: 15px; padding-bottom: 15px; margin-top: -15px; margin-bottom: -15px; }
  .wordmark { padding: 12px 0; margin: -12px 0; }
  .beat__back { display: inline-block; padding: 14px 0; margin: -14px 0; }
  .cx-card .cx-card__close { padding: 16px .6em; margin: -16px -.6em; }   /* (beats crystals.css, loaded later) */
}

/* ---------------------------------------------------------------- reduced motion */
/* the way back at the end of the track, only where there is no loop */
.beat--back { display: none; }
.beat__back { pointer-events: auto; text-decoration: none; color: var(--ink); }
.beat__back:hover, .beat__back:focus-visible { text-decoration: underline; text-underline-offset: .35em; }
/* the HUD's two-colour ring (pass 3: the glow ring measured ~2:1 on snow) */
.beat__back:focus-visible {
  outline: 2px solid var(--ink); outline-offset: 6px; border-radius: 2px;
  box-shadow: 0 0 0 10px var(--halo, rgba(10, 16, 22, .45));
}

@media (prefers-reduced-motion: reduce) {
  .beat--back { display: block; }
  .gl { display: none; }
  .beat--hero { transition: none; }
  .manifesto[open], .manifesto[open]::backdrop { animation: none; }
  .sound[aria-pressed="true"] .sound__bars i { animation: none; height: 5px; }
  .sound[aria-pressed="true"] .sound__bars i:nth-child(even) { height: 3px; }
}
