/* fx.css: the polish layer (agent P). Pairs with js/fx/index.js; hooks are documented there.
   Page transitions, the sky canvas, film grain and scanlines, the targeting reticle, heading
   decode, counters, light sweeps, the sound button and the trailer modal.
   Reduced motion turns every animation here off; the page still works and still looks right. */

:root {
  --fx-mono: var(--font-hud, var(--font-mono, "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace));
  --fx-amber: 255, 184, 38;
  --fx-magenta: 255, 64, 115;
  --fx-star: 148, 219, 255;
  --fx-text: 217, 224, 242;
  --fx-ease: cubic-bezier(0.16, 1, 0.3, 1);        /* ease-out-expo */
  --fx-ease-quart: cubic-bezier(0.25, 1, 0.5, 1);
  --fx-z-grain: 2147482000;
  --fx-z-reticle: 2147482500;
  --fx-z-warp: 2147483000;
}

.fx-visually-hidden {
  position: absolute !important; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ================================================================ page transitions */

/* Round 2 (agent W): a soft monochrome dip, no flash. One curve (ease-in-out cubic) for the whole
   jump: the old page dips to near-black in 380ms, the browser navigates, and the new page rises
   out of the same near-black in 420ms. The veil is html::before, so it runs on the compositor
   and never waits for JavaScript. On the new page the inline script at the top of the header
   partial sets html.fx-arrive before the first paint (the veil holds dark), then html.fx-arrive-go
   once that dark frame is on screen (the veil fades out), so a heavy page that boots slowly never
   cuts in lit. The starlight streaks are a canvas on top
   (js/fx/transitions.js). The two dark frames meet in a short plain View Transition crossfade;
   no scale, blur or brightness, and the header is part of the dip (no named header group, which
   would pop out of the veil mid-jump). */
:root {
  --fx-warp-ease: cubic-bezier(0.65, 0, 0.35, 1);  /* ease-in-out cubic (= inOut() in the JS) */
  --fx-warp-in: 380ms;                              /* = DIP_IN_MS */
  --fx-warp-out: 420ms;                             /* = DIP_OUT_MS */
  --fx-veil-max: 0.92;                              /* = VEIL_MAX */
}

@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 260ms;
  animation-timing-function: var(--fx-warp-ease);
}

@media (prefers-reduced-motion: no-preference) {
  html.fx-depart::before,
  html.fx-arrive::before,
  html.fx-veil-hold::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: calc(var(--fx-z-warp) - 1);
    pointer-events: none;
    background: radial-gradient(ellipse 120% 90% at 50% 50%, rgb(8 10 18) 0%, rgb(4 5 10) 55%, rgb(2 3 6) 100%);
    opacity: 0;
  }
  html.fx-depart::before { animation: fx-veil-in var(--fx-warp-in) var(--fx-warp-ease) both; }
  html.fx-arrive::before { opacity: var(--fx-veil-max); }
  html.fx-arrive.fx-arrive-go::before { animation: fx-veil-out var(--fx-warp-out) var(--fx-warp-ease) both; }
  html.fx-veil-hold::before { opacity: var(--fx-veil, 0); }
}
@keyframes fx-veil-in { from { opacity: 0; } to { opacity: var(--fx-veil-max); } }
@keyframes fx-veil-out { from { opacity: var(--fx-veil-max); } to { opacity: 0; } }

@media print {
  html.fx-depart::before, html.fx-arrive::before, html.fx-veil-hold::before { display: none; }
}

.fx-warp {
  position: fixed;
  inset: 0;
  z-index: var(--fx-z-warp);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
}
.fx-warp.is-on { opacity: 1; visibility: visible; }
.fx-warp canvas { display: block; width: 100%; height: 100%; }

/* ================================================================ the sky */

.fx-sky {
  position: fixed;
  inset: 0;
  z-index: -1;
  display: block;
  width: 100%;
  height: 100vh;
  height: 100lvh;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.4s var(--fx-ease-quart);
}
.fx-sky.is-ready { opacity: 1; }

/* ================================================================ grain + scanlines */
/* One fixed, static layer: no animation, no blend mode, so scrolling never repaints it. */

html::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: var(--fx-z-grain);
  pointer-events: none;
  opacity: 0.55;
  background-image:
    repeating-linear-gradient(to bottom, rgba(var(--fx-text), 0.022) 0 1px, transparent 1px 3px),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.11 -0.035'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  background-size: auto, 180px 180px;
}

/* ================================================================ targeting reticle */

.fx-reticle {
  --rc: var(--fx-star);
  position: fixed;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  z-index: var(--fx-z-reticle);
  pointer-events: none;
  opacity: 0;
  transition: opacity 200ms ease;
}
.fx-reticle.is-on { opacity: 1; }
.fx-reticle.is-hidden { opacity: 0; }
.fx-reticle.is-amber { --rc: var(--fx-amber); }

.fx-reticle-c {
  position: absolute;
  left: 0;
  top: 0;
  width: 7px;
  height: 7px;
  border: 0 solid rgba(var(--rc), 0.8);
  will-change: transform;
  transition: width 200ms var(--fx-ease), height 200ms var(--fx-ease), border-color 180ms ease;
}
.fx-reticle-c0 { border-top-width: 1.5px; border-left-width: 1.5px; }
.fx-reticle-c1 { border-top-width: 1.5px; border-right-width: 1.5px; translate: -100% 0; }
.fx-reticle-c2 { border-bottom-width: 1.5px; border-right-width: 1.5px; translate: -100% -100%; }
.fx-reticle-c3 { border-bottom-width: 1.5px; border-left-width: 1.5px; translate: 0 -100%; }
.fx-reticle.is-locked .fx-reticle-c { width: 11px; height: 11px; border-color: rgba(var(--rc), 1); }

.fx-reticle-x {
  position: absolute;
  left: 0;
  top: 0;
  width: 11px;
  height: 11px;
  margin: -5.5px 0 0 -5.5px;
  will-change: transform;
  transition: opacity 180ms ease;
  --arm: linear-gradient(rgba(var(--rc), 0.75), rgba(var(--rc), 0.75));
  background:
    var(--arm) 50% 0 / 1px 3.5px no-repeat,
    var(--arm) 50% 100% / 1px 3.5px no-repeat,
    var(--arm) 0 50% / 3.5px 1px no-repeat,
    var(--arm) 100% 50% / 3.5px 1px no-repeat;
}
.fx-reticle.is-locked .fx-reticle-x { opacity: 0; }

/* ================================================================ heading decode */

/* Headings and counters wait (hidden) for fx to take them over, so the final text never
   flashes before its animation. A failsafe shows them after 2.5s if fx never arrives. */
@media (prefers-reduced-motion: no-preference) {
  html.js [data-decode]:not(.fx-decode-armed):not(.is-decoding):not(.is-decoded),
  html.js [data-count-to]:not(.fx-count-ready) {
    opacity: 0;
    animation: fx-failsafe 0s linear 2.5s forwards;
  }
}
@keyframes fx-failsafe { to { opacity: 1; } }
html.fx-on:not(.fx-reduced) .fx-decode-armed { opacity: 0; }

.fx-dc { position: relative; }
.fx-dc:not(.is-set) { color: transparent; -webkit-text-fill-color: transparent; }
.fx-dc.is-wait::after { content: none; }
.fx-dc:not(.is-set):not(.is-wait)::after {
  content: attr(data-g);
  content: attr(data-g) / "";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--fx-mono);
  font-weight: 500;
  font-size: 0.62em;
  line-height: 1;
  letter-spacing: 0;
  color: rgba(var(--fx-star), 0.75);
  -webkit-text-fill-color: currentColor;
  pointer-events: none;
}
.fx-dc.is-scan::after {
  color: rgba(var(--fx-amber), 1);
  text-shadow: 0 0 10px rgba(var(--fx-amber), 0.8);
}
.fx-dc.is-set { animation: fx-dc-set 420ms var(--fx-ease) both; }
@keyframes fx-dc-set {
  from { text-shadow: 0 0 18px rgba(var(--fx-star), 0.9); filter: brightness(1.8); }
  to { text-shadow: none; filter: none; }
}

/* ================================================================ counters */

.fx-count {
  display: inline-block;
  font-variant-numeric: tabular-nums;
  text-align: inherit;
}

/* ================================================================ light sweeps */

/* Logo: a band of light, masked to the image's own alpha (set by sweep.js). */
:where(.fx-sweep) { position: relative; }
.fx-sweep-band {
  position: absolute;
  pointer-events: none;
  overflow: hidden;
  -webkit-mask: var(--fx-mask) center / 100% 100% no-repeat;
  mask: var(--fx-mask) center / 100% 100% no-repeat;
  mix-blend-mode: screen;
  mix-blend-mode: plus-lighter;
}
.fx-sweep-band::before {
  content: "";
  position: absolute;
  top: -10%;
  bottom: -10%;
  left: 0;
  width: 34%;
  background: linear-gradient(100deg,
    transparent 0%,
    rgba(255, 236, 200, 0.10) 30%,
    rgba(255, 246, 228, 0.85) 50%,
    rgba(255, 236, 200, 0.10) 70%,
    transparent 100%);
  transform: translateX(-110%) skewX(-16deg);
  animation: fx-logo-sweep 6.2s var(--fx-ease-quart) 1.4s infinite;
}
@keyframes fx-logo-sweep {
  0% { transform: translateX(-110%) skewX(-16deg); }
  24%, 100% { transform: translateX(310%) skewX(-16deg); }
}

/* Call to action: a sheen crosses on hover (idle on large buttons), a pulse ring goes out.
   The sheen blends with `overlay`: the amber face brightens, the dark label stays dark. */
:where(.fx-cta) { position: relative; }
.fx-cta-sweep {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  pointer-events: none;
  mix-blend-mode: overlay;
}
.fx-cta-sweep::before {
  content: "";
  position: absolute;
  top: -30%;
  bottom: -30%;
  left: 0;
  width: 45%;
  background: linear-gradient(100deg, transparent 0%, rgba(255, 246, 228, 0.35) 30%, rgba(255, 246, 228, 0.95) 50%, rgba(255, 246, 228, 0.35) 70%, transparent 100%);
  transform: translateX(-130%) skewX(-18deg);
}
.fx-cta:not(.cta-sm) .fx-cta-sweep::before {
  animation: fx-cta-idle 7.4s var(--fx-ease-quart) 2.6s infinite;
}
.fx-cta:hover .fx-cta-sweep::before,
.fx-cta:focus-visible .fx-cta-sweep::before {
  animation: fx-cta-sweep 760ms var(--fx-ease) both;
}
@keyframes fx-cta-sweep {
  from { transform: translateX(-130%) skewX(-18deg); }
  to { transform: translateX(330%) skewX(-18deg); }
}
@keyframes fx-cta-idle {
  0%, 84% { transform: translateX(-130%) skewX(-18deg); }
  100% { transform: translateX(330%) skewX(-18deg); }
}
.fx-cta-pulse {
  position: absolute;
  inset: -1px;
  border: 1px solid rgba(var(--fx-amber), 0.95);
  border-radius: inherit;
  opacity: 0;
  pointer-events: none;
}
.fx-cta-hot .fx-cta-pulse { animation: fx-cta-pulse 820ms var(--fx-ease) both; }
@keyframes fx-cta-pulse {
  0% { opacity: 0.95; transform: scale(1, 1); box-shadow: 0 0 0 0 rgba(var(--fx-amber), 0.45); }
  100% { opacity: 0; transform: scale(1.1, 1.45); box-shadow: 0 0 22px 6px rgba(var(--fx-amber), 0); }
}

/* ================================================================ sound button */

.fx-audio {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  height: 2.25rem;
  padding: 0 0.7rem;
  border: 1px solid rgba(var(--fx-star), 0.2);
  border-radius: 2px;
  background: rgba(5, 6, 10, 0.25);
  color: rgba(var(--fx-text), 0.82);
  font: 500 0.66rem/1 var(--fx-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color 180ms ease, color 180ms ease, background-color 180ms ease;
}
.fx-audio[hidden] { display: none; }
.fx-audio:hover { border-color: rgba(var(--fx-star), 0.5); color: rgb(var(--fx-text)); }
.fx-audio:focus-visible { outline: 2px solid rgb(var(--fx-amber)); outline-offset: 3px; }
.fx-audio.is-on { border-color: rgba(var(--fx-amber), 0.45); color: rgb(var(--fx-text)); }
.fx-eq {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 13px;
}
.fx-eq i {
  display: block;
  width: 2px;
  height: 100%;
  background: currentColor;
  opacity: 0.45;
  transform: scaleY(var(--eq-off, 0.3));
  transform-origin: 50% 100%;
  transition: transform 300ms var(--fx-ease), background-color 200ms ease;
}
.fx-audio.is-on .fx-eq i {
  background: rgb(var(--fx-amber));
  opacity: 1;
  animation: fx-eq 900ms ease-in-out infinite alternate;
}
.fx-eq i:nth-child(2) { --eq-off: 0.55; }
.fx-eq i:nth-child(3) { --eq-off: 0.85; }
.fx-eq i:nth-child(4) { --eq-off: 0.55; }
.fx-audio:hover .fx-eq i { opacity: 0.75; }
.fx-audio.is-on .fx-eq i:nth-child(2) { animation-duration: 640ms; animation-delay: -200ms; }
.fx-audio.is-on .fx-eq i:nth-child(3) { animation-duration: 1100ms; animation-delay: -500ms; }
.fx-audio.is-on .fx-eq i:nth-child(4) { animation-duration: 760ms; animation-delay: -100ms; }
.fx-audio.is-on .fx-eq i:nth-child(5) { animation-duration: 980ms; animation-delay: -650ms; }
.fx-audio.is-waiting .fx-eq i { animation-play-state: paused; opacity: 0.5; }
@keyframes fx-eq {
  0% { transform: scaleY(0.2); }
  50% { transform: scaleY(0.9); }
  100% { transform: scaleY(0.45); }
}
@media (max-width: 720px) {
  .fx-audio { padding: 0 0.6rem; }
  .fx-audio-label { display: none; }
}

/* ================================================================ trailer modal */

html.fx-modal-open { overflow: hidden; }

.fx-trailer {
  --bar: min(11vh, 104px);
  --fw: min(90vw, calc((100dvh - 2 * var(--bar) - 5.5rem) * 16 / 9), 1480px);
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  height: 100dvh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  overflow: hidden;
  background: transparent;
  color: rgb(var(--fx-text));
}
.fx-trailer::backdrop {
  background: rgba(3, 4, 8, 0.62);
  -webkit-backdrop-filter: blur(18px) saturate(0.75) brightness(0.8);
  backdrop-filter: blur(18px) saturate(0.75) brightness(0.8);
  animation: fx-fade-in 420ms var(--fx-ease-quart) both;
}
.fx-trailer.is-closing::backdrop { animation: fx-fade-out 320ms ease both; }

.fx-trailer-bar {
  position: absolute;
  left: 0;
  right: 0;
  height: var(--bar);
  background: #000;
  animation: fx-bar-in 560ms var(--fx-ease) both;
}
.fx-trailer-bar.is-top { top: 0; --from: -100%; }
.fx-trailer-bar.is-bottom { bottom: 0; --from: 100%; }
.fx-trailer.is-closing .fx-trailer-bar { animation: fx-bar-out 300ms ease-in both; }

.fx-trailer-stage {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 0.9rem;
}
.fx-trailer-frame {
  position: relative;
  width: var(--fw);
  aspect-ratio: 16 / 9;
  background: #000;
  box-shadow: 0 30px 120px rgba(0, 0, 0, 0.7);
  animation: fx-frame-in 760ms var(--fx-ease) 120ms both;
}
.fx-trailer.is-closing .fx-trailer-frame { animation: fx-frame-out 300ms ease-in both; }
.fx-trailer-frame > iframe,
.fx-trailer-frame > video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  background: #000;
  object-fit: contain;
}
.fx-tick {
  position: absolute;
  width: 14px;
  height: 14px;
  border: 0 solid rgba(var(--fx-star), 0.7);
  pointer-events: none;
}
.fx-tick.is-tl { left: -8px; top: -8px; border-top-width: 1px; border-left-width: 1px; }
.fx-tick.is-tr { right: -8px; top: -8px; border-top-width: 1px; border-right-width: 1px; }
.fx-tick.is-bl { left: -8px; bottom: -8px; border-bottom-width: 1px; border-left-width: 1px; }
.fx-tick.is-br { right: -8px; bottom: -8px; border-bottom-width: 1px; border-right-width: 1px; }

.fx-trailer-hud {
  width: var(--fw);
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font: 500 0.7rem/1 var(--fx-mono);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(var(--fx-text), 0.7);
  animation: fx-fade-in 500ms ease 520ms both;
}
.fx-trailer-rec {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgb(var(--fx-magenta));
  box-shadow: 0 0 10px rgba(var(--fx-magenta), 0.9);
  animation: fx-blink 1.6s steps(2, jump-none) infinite;
  order: -1;
}

.fx-trailer-close {
  position: absolute;
  top: calc(var(--bar) / 2);
  right: clamp(1rem, 3vw, 2.5rem);
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.55rem 0.8rem;
  border: 1px solid rgba(var(--fx-text), 0.25);
  border-radius: 2px;
  background: rgba(0, 0, 0, 0.35);
  color: rgb(var(--fx-text));
  font: 600 0.72rem/1 var(--fx-mono);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
  z-index: 2;
  animation: fx-fade-in 400ms ease 300ms both;
  transition: border-color 180ms ease, background-color 180ms ease;
}
.fx-trailer-close:hover { border-color: rgba(var(--fx-amber), 0.8); background: rgba(var(--fx-amber), 0.1); }
.fx-trailer-close:focus-visible { outline: 2px solid rgb(var(--fx-amber)); outline-offset: 3px; }
.fx-trailer-close kbd {
  font: inherit;
  font-size: 0.6rem;
  padding: 0.2rem 0.35rem;
  border: 1px solid rgba(var(--fx-text), 0.3);
  color: rgba(var(--fx-text), 0.7);
}

@keyframes fx-fade-in { from { opacity: 0; } }
@keyframes fx-fade-out { to { opacity: 0; } }
@keyframes fx-bar-in { from { transform: translateY(var(--from)); } }
@keyframes fx-bar-out { to { transform: translateY(var(--from)); } }
@keyframes fx-frame-in {
  from { clip-path: inset(50% 0 50% 0); opacity: 0.4; transform: scale(0.985); }
  to { clip-path: inset(-24px -24px -24px -24px); opacity: 1; transform: none; }
}
@keyframes fx-frame-out {
  to { clip-path: inset(50% 0 50% 0); opacity: 0; }
}
@keyframes fx-blink { 50% { opacity: 0.25; } }

@media (max-width: 640px) {
  .fx-trailer { --fw: 100vw; --bar: 64px; }
  .fx-tick { display: none; }
  .fx-trailer-hud { padding: 0 1rem; }
}

/* ================================================================ reduced motion, print, forced colours */

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  .fx-warp, .fx-reticle { display: none !important; }
  .fx-decode-armed { opacity: 1 !important; }
  .fx-sweep-band, .fx-cta-sweep, .fx-cta-pulse { display: none; }
  .fx-sky { transition: none; }
  .fx-audio.is-on .fx-eq i { animation: none; transform: scaleY(0.7); }
  .fx-trailer::backdrop, .fx-trailer-bar, .fx-trailer-frame, .fx-trailer-hud, .fx-trailer-close, .fx-trailer-rec {
    animation: none !important;
  }
}

@media print {
  html::after, .fx-sky, .fx-warp, .fx-reticle, .fx-audio { display: none !important; }
  .fx-decode-armed { opacity: 1 !important; }
}

@media (forced-colors: active) {
  html::after, .fx-sky, .fx-sweep-band, .fx-cta-sweep, .fx-cta-pulse, .fx-reticle { display: none !important; }
}
