/* Cog Wars pre-boot loading shell -- theme (S-05).
 *
 * A BLOCKING stylesheet in <head> on purpose. It is what makes the first paint
 * the themed screen rather than white, which is APU-144's "no blank frame".
 * Deferring or inlining-later would trade the one property this file exists for.
 *
 * No @import, no webfont, no external URL: every additional network round trip
 * before first paint is a window in which the blank frame can appear, and under
 * COEP require-corp a cross-origin font would additionally need CORP and would
 * fail SILENTLY without it (the S-04 enumeration's standing constraint). The
 * type stack is system fonts for exactly that reason -- it is a deliberate
 * constraint, not a placeholder to be "improved" later.
 */

:root {
  --cw-void: #05060b;
  --cw-ink: #d8e4ff;
  --cw-dim: #7f8cb5;
  --cw-neon: #63f0d8;
  --cw-neon-2: #b06cff;
  --cw-plate: rgba(8, 10, 20, 0.72);
}

/* The background sits on <html>, not on a child. The browser paints the root
 * element's background before anything else, so there is no frame in which the
 * canvas area is the browser's default white.
 *
 * D9, 2026-07-30 -- THE ABOVE WAS FALSE UNTIL THIS RULE WAS REPAIRED, AND IT
 * SHIPPED THAT WAY. Every child of <body> here is position:fixed (.cw-shell,
 * .cw-canvas), so the root box measured 1279x0 in a driven browser. A solid
 * background-COLOUR fills the canvas unconditionally, but a background-IMAGE is
 * sized by the root's background POSITIONING AREA -- and a gradient painted into
 * a zero-height area paints nothing, so the canvas fell back to the browser's
 * default WHITE. The loading screen was rendered on white: the plate read
 * rgba(8,10,20,0.72) over white = (77,78,85), the notice scrim
 * rgba(3,4,9,0.86) over white = (39,39,44). The old AC[0] gate passed it because
 * white-plus-rings-plus-plate is high-variance, which is D8's error seen from the
 * other side: the criterion is `the themed screen is on the screen`, and variance
 * cannot say that.
 *
 * TWO declarations repair it, and they are not redundant:
 *
 *   height: 100%       gives the root a real box, so the AUTHORED gradient paints
 *                      as designed. This is what makes the centre glow exist.
 *
 *   background-color   makes the property AC[0] actually protects -- never the
 *                      browser's white -- hold STRUCTURALLY. A colour has no
 *                      positioning area, so no future layout change can take it
 *                      away, which is precisely the failure that happened here.
 *                      Its cost is stated honestly: if the gradient ever stops
 *                      painting again the screen degrades to a flat --cw-void
 *                      field with the shell on it, and AC[0] will pass that,
 *                      correctly -- it is the themed screen, just without the
 *                      glow. The gradient's SHAPE is cosmetic; not being white is
 *                      not, and only one of the two can be made unloseable.
 *
 * Longhands, NOT the `background` shorthand: the shorthand resets
 * background-color to transparent, so `background: <gradient>` followed by
 * nothing is exactly the state this defect was in. */
html {
  height: 100%;
  background-color: var(--cw-void);
  background-image: radial-gradient(ellipse at 50% 42%, #101a34 0%, #070912 55%, var(--cw-void) 100%);
  color: var(--cw-ink);
}

body {
  margin: 0;
  padding: 0;
  overflow: hidden;
  font-family: "DejaVu Sans", "Liberation Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  background: transparent;
}

.cw-shell {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
}

/* Sacred-geometry rings + bloom. Slow, continuous, low-contrast: this screen is
 * shown to a player who has NOT yet been offered the reduce-flash toggle, so it
 * must not itself be the thing the notice warns about. Nothing here strobes,
 * nothing crosses ~1Hz, and opacity never approaches a hard on/off. That is a
 * constraint from the notice's own existence, not an aesthetic choice. */
.cw-field {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

.cw-ring {
  position: absolute;
  left: 50%;
  top: 50%;
  border-radius: 50%;
  border: 1px solid rgba(99, 240, 216, 0.20);
  transform: translate(-50%, -50%);
  animation: cw-breathe 9s ease-in-out infinite;
}

.cw-ring-a { width: 46vmin; height: 46vmin; animation-delay: 0s; }
.cw-ring-b { width: 66vmin; height: 66vmin; border-color: rgba(176, 108, 255, 0.16); animation-delay: -3s; }
.cw-ring-c { width: 86vmin; height: 86vmin; border-color: rgba(99, 240, 216, 0.10); animation-delay: -6s; }

.cw-bloom {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 30vmin;
  height: 30vmin;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(99, 240, 216, 0.16) 0%, rgba(99, 240, 216, 0) 70%);
  animation: cw-breathe 11s ease-in-out infinite;
}

@keyframes cw-breathe {
  0%   { opacity: 0.55; transform: translate(-50%, -50%) scale(0.97); }
  50%  { opacity: 0.95; transform: translate(-50%, -50%) scale(1.03); }
  100% { opacity: 0.55; transform: translate(-50%, -50%) scale(0.97); }
}

/* Honour the OS-level preference. This is not the reduce-flash toggle (S-79
 * owns that, and it does not exist yet); it is the one accessibility signal the
 * shell can read without any game code, at the exact moment the game cannot yet
 * offer its own. Costs nothing and is the right default. */
@media (prefers-reduced-motion: reduce) {
  .cw-ring, .cw-bloom { animation: none; opacity: 0.7; }
}

.cw-plate {
  position: relative;
  z-index: 3;
  text-align: center;
  padding: 4vmin 6vmin;
  border-radius: 2px;
  background: var(--cw-plate);
  box-shadow: 0 0 60px rgba(99, 240, 216, 0.06);
}

.cw-title {
  margin: 0;
  font-size: clamp(28px, 7vmin, 68px);
  font-weight: 300;
  letter-spacing: 0.42em;
  text-indent: 0.42em;
  color: var(--cw-ink);
  text-shadow: 0 0 22px rgba(99, 240, 216, 0.45);
}

.cw-sub {
  margin: 1.2em 0 2.2em;
  font-size: clamp(11px, 1.7vmin, 15px);
  letter-spacing: 0.30em;
  text-indent: 0.30em;
  text-transform: uppercase;
  color: var(--cw-dim);
}

.cw-meter {
  width: min(52vmin, 420px);
  height: 2px;
  margin: 0 auto;
  background: rgba(216, 228, 255, 0.12);
  overflow: hidden;
}

.cw-meter-fill {
  width: 0%;
  height: 100%;
  background: linear-gradient(90deg, var(--cw-neon), var(--cw-neon-2));
  transition: width 220ms linear;
}

.cw-pct {
  margin: 1.1em 0 0;
  font-size: clamp(10px, 1.5vmin, 13px);
  letter-spacing: 0.22em;
  color: var(--cw-dim);
  font-variant-numeric: tabular-nums;
}

/* -- the notice -----------------------------------------------------------
 * Hidden by DEFAULT here, and revealed by the html.cw-notice-due class that the
 * head script stamps before <body> is parsed. Chosen this way round so that a
 * catastrophic script failure fails CLOSED on the notice and OPEN on the game:
 * a player who never sees the notice because the shell broke is worse served
 * than one who sees it twice, but a player permanently trapped behind an
 * un-dismissable modal cannot play at all. The script is a few lines and runs
 * before paint; this is the residual-risk ordering, not the expected path. */
.cw-notice { display: none; }

html.cw-notice-due .cw-notice {
  display: flex;
  position: absolute;
  inset: 0;
  z-index: 5;
  align-items: center;
  justify-content: center;
  background: rgba(3, 4, 9, 0.86);
}

.cw-notice-inner {
  max-width: 62ch;
  padding: 5vmin;
  text-align: left;
  border: 1px solid rgba(99, 240, 216, 0.22);
  background: #070912;
}

.cw-notice-h {
  margin: 0 0 1.2em;
  font-size: clamp(15px, 2.6vmin, 22px);
  font-weight: 400;
  letter-spacing: 0.20em;
  text-transform: uppercase;
  color: var(--cw-neon);
}

.cw-notice-line {
  margin: 0 0 1em;
  font-size: clamp(13px, 2vmin, 16px);
  line-height: 1.65;
  color: var(--cw-ink);
}

.cw-notice-ok {
  margin-top: 1.6em;
  padding: 0.9em 2.2em;
  font: inherit;
  font-size: clamp(12px, 1.8vmin, 15px);
  letter-spacing: 0.14em;
  color: var(--cw-void);
  background: var(--cw-neon);
  border: 0;
  cursor: pointer;
}

.cw-notice-ok:hover,
.cw-notice-ok:focus-visible {
  background: #8ff7e6;
  outline: 2px solid var(--cw-neon-2);
  outline-offset: 3px;
}

/* -- the canvas ----------------------------------------------------------
 * Present from the first paint so Unity can attach to it immediately, without the
 * shell having to hand over a freshly-created element mid-load.
 *
 * THE RULE, AND IT BINDS EVERY FUTURE STEP: the canvas MUST NOT PAINT BEFORE THE
 * REVEAL. Not "must be behind the shell" -- behind is not enough, and the earlier
 * version of this comment claimed "until then the canvas is a transparent layer
 * nobody sees", which was false. .cw-shell is a TRANSPARENT flex container at
 * z-index 2; the page's only opaque backdrop is the gradient on <html>. So the
 * instant Unity painted its first frame, the canvas became the loading screen's
 * own background and the game was visible at 14% through an 86%-opaque
 * photosensitivity notice the player had not acknowledged. A driven run caught it
 * by diffing screenshots; seven static checks and every reading of the reveal
 * logic had passed, because the reveal logic was correct. Gating the TEARDOWN of
 * the loading screen was never the same thing as gating RENDERING.
 *
 * visibility, NOT display. `display: none` gives the canvas a zero client rect,
 * Unity's resize observer reshapes the framebuffer to 0x0, and the game runs at
 * 0x0 until the reveal -- a worse defect, and one the screenshot diff that catches
 * the original scores as a PERFECT PASS, because two frames of a 0x0 game are
 * identical. `visibility: hidden` suppresses paint and preserves the box, which is
 * the property actually wanted.
 *
 * FOR S-47 AND ANYTHING ELSE THAT WANTS TO DRAW DURING THE LOAD: warmup still runs.
 * This suppresses PRESENTATION, not work -- WebGL commands, shader compilation and
 * variant warmup all execute normally against a hidden canvas. What is not
 * available is showing the player anything on it before the reveal. Whatever wants
 * that has to earn it against AC[3], not by relaxing this rule.
 *
 * tools/check_loading_shell.py CHECK 9 holds this statically, and drive_shell.py's
 * counterfactual probe holds it in photons: with the notice up and the instance
 * ready, hiding the canvas must not change the screen. */
.cw-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 1;
  background: transparent;
  visibility: hidden;
}

html.cw-running .cw-canvas { visibility: visible; }
html.cw-running .cw-shell { display: none; }
html.cw-running { overflow: hidden; }

/* BEGIN GENERATED cw-failure-surface -- tools/gen_failure_surface.py */
/* Generated from docs/deploy/failure-copy.json. DO NOT EDIT BY HAND. */

/* Hidden by DEFAULT and by the `hidden` attribute both -- belt and braces,
 * because this stylesheet failing to load must not turn the page into
 * eighteen stacked failure panels. Failing closed here is free; the
 * notice's opposite choice in the block above is reasoned separately. */
.cw-fail { display: none; }

html.cw-failed[data-fail-active="F-01"] #cw-fail-F-01 { display: flex; }
html.cw-failed[data-fail-active="F-02"] #cw-fail-F-02 { display: flex; }
html.cw-failed[data-fail-active="F-05"] #cw-fail-F-05 { display: flex; }
html.cw-failed[data-fail-active="F-06"] #cw-fail-F-06 { display: flex; }
html.cw-failed[data-fail-active="F-07"] #cw-fail-F-07 { display: flex; }
html.cw-failed[data-fail-active="F-08"] #cw-fail-F-08 { display: flex; }
html.cw-failed[data-fail-active="F-09"] #cw-fail-F-09 { display: flex; }
html.cw-failed[data-fail-active="F-10"] #cw-fail-F-10 { display: flex; }
html.cw-failed[data-fail-active="F-17"] #cw-fail-F-17 { display: flex; }
html.cw-failed[data-fail-active="F-18"] #cw-fail-F-18 { display: flex; }
html.cw-failed[data-fail-active="F-ENGINE"] #cw-fail-F-ENGINE { display: flex; }

html[data-fail-degraded~="F-03"] #cw-fail-F-03 { display: block; }
html[data-fail-degraded~="F-04"] #cw-fail-F-04 { display: block; }
html[data-fail-degraded~="F-11"] #cw-fail-F-11 { display: block; }
html[data-fail-degraded~="F-12"] #cw-fail-F-12 { display: block; }
html[data-fail-degraded~="F-13"] #cw-fail-F-13 { display: block; }
html[data-fail-degraded~="F-14"] #cw-fail-F-14 { display: block; }
html[data-fail-degraded~="F-15"] #cw-fail-F-15 { display: block; }
html[data-fail-degraded~="F-16"] #cw-fail-F-16 { display: block; }

/* A terminal panel replaces the screen. The loading shell and the canvas
 * both go: a meter that is still filling behind a `this is over` message
 * contradicts it, and a frozen last frame reads as a hang.
 *
 * THE CANVAS USES visibility, NOT display, AND THE GATE CAUGHT ME GETTING
 * THIS WRONG. The first version of this generator emitted
 * `html.cw-failed .cw-canvas { display: none }` and
 * check_loading_shell.py's CANVAS check rejected it by name. `display: none`
 * gives the canvas a zero client rect, Unity's resize observer reshapes the
 * framebuffer to 0x0, and the game runs at 0x0. That is survivable for a
 * TERMINAL row -- the run is over anyway -- but the rule exists precisely
 * because the pixel diff that catches the original defect scores two frames
 * of a 0x0 game as a PERFECT PASS. Carving out an exception `because this
 * one is terminal` would put a hole in the one check that can see it, on
 * the argument that this instance is harmless. The instances are never the
 * problem; the hole is. .cw-shell keeps display:none because it is not a
 * canvas and has no framebuffer to lose. */
html.cw-failed .cw-shell { display: none; }
html.cw-failed .cw-canvas { visibility: hidden; }

.cw-fail-terminal {
  position: fixed;
  inset: 0;
  z-index: 10;
  align-items: center;
  justify-content: center;
  background: var(--cw-void);
}

/* Soft rows sit ON TOP of a running game, so they are small, corner-anchored
 * and never modal. A degraded row that blocks input would convert `you lost
 * the sound` into `you lost the game`. */
.cw-fail-degraded,
.cw-fail-recoverable {
  position: fixed;
  left: 2vmin;
  bottom: 2vmin;
  z-index: 11;
  max-width: 44ch;
  pointer-events: none;
  background: var(--cw-plate);
  border: 1px solid rgba(99, 240, 216, 0.22);
}

.cw-fail-inner {
  max-width: 62ch;
  padding: 4vmin;
  text-align: left;
}

.cw-fail-degraded .cw-fail-inner,
.cw-fail-recoverable .cw-fail-inner { padding: 2.2vmin 2.6vmin; }

.cw-fail-h {
  margin: 0 0 1.2em;
  font-size: clamp(15px, 2.6vmin, 22px);
  font-weight: 400;
  letter-spacing: 0.20em;
  text-transform: uppercase;
  color: var(--cw-neon);
}

.cw-fail-degraded .cw-fail-h,
.cw-fail-recoverable .cw-fail-h {
  margin-bottom: 0.6em;
  font-size: clamp(11px, 1.6vmin, 14px);
}

.cw-fail-b {
  margin: 0;
  font-size: clamp(13px, 2vmin, 16px);
  line-height: 1.65;
  color: var(--cw-ink);
}

.cw-fail-degraded .cw-fail-b,
.cw-fail-recoverable .cw-fail-b { font-size: clamp(11px, 1.6vmin, 14px); }

.cw-fail-a {
  margin-top: 1.6em;
  padding: 0.9em 2.2em;
  font: inherit;
  font-size: clamp(12px, 1.8vmin, 15px);
  letter-spacing: 0.14em;
  color: var(--cw-void);
  background: var(--cw-neon);
  border: 0;
  cursor: pointer;
}

.cw-fail-a:hover,
.cw-fail-a:focus-visible {
  background: #8ff7e6;
  outline: 2px solid var(--cw-neon-2);
  outline-offset: 3px;
}
/* END GENERATED cw-failure-surface */
