/*
 * SPARTICUS — game/style.css
 *
 * WHAT THIS FILE IS RESPONSIBLE FOR, AND WHAT IT IS NOT.
 *
 * The play field, the HUD and the four touch controls are drawn on the canvas in FIELD units,
 * because DESIGN §0.2 makes one sim unit one CSS pixel and §8.5 states the occlusion boxes in the
 * same numbers. Nothing in this stylesheet may move a control, resize a hit target or change a
 * readability floor — those are rules, they live in `RULES` and in `data/layout.js`, and a CSS
 * rule that could contradict them would be a second source of truth for the geometry the game is
 * balanced against.
 *
 * So this file styles exactly one thing: the SCREENS around the canvas — title, deck select, the
 * ascent, pause, the tallies, settings. Chrome, in brass.
 *
 * ────────────────────────────────────────────────────────────────────────────────────────────
 * NO HORIZONTAL SCROLL, EVER, AND 44 px IS A FLOOR RATHER THAN A TARGET (web-game.md §7)
 * ────────────────────────────────────────────────────────────────────────────────────────────
 * `overflow-x: hidden` on the root is not the fix, it is the seatbelt; every rule below is
 * written so nothing can exceed the viewport in the first place. Buttons carry `min-height:44px`
 * and `min-width:44px` directly rather than inheriting it from a container, because the failure
 * mode is one button in one screen shrinking under a flex rule somebody added later.
 *
 * ────────────────────────────────────────────────────────────────────────────────────────────
 * ORDER-DEPENDENT RULES ARE WRITTEN AS ONE RULE (web-game.md §9, QUAL-244)
 * ────────────────────────────────────────────────────────────────────────────────────────────
 * The device lab photographed a CSS fix that HALF-WON — equal specificity, earlier source order,
 * `overflow-y` applied and `justify-content` silently lost — while the assertion suite stayed
 * green throughout. Where two properties must both take, they are set in the same declaration
 * block on the same selector, so there is no cascade for one of them to lose.
 */

/* ═════════════════════════════════════════════════════════ the palette, once */

/*
 * These are the CHROME colours and they are the only hex literals in this project outside
 * `data/palette.js`. They deliberately do NOT include the two reserved ordnance bands: the cold
 * cyan-white belongs to the Interceptor and the molten ochre to the Concord, both of them are
 * read out of `RULES.PALETTE_BANDS` by the renderer, and a stylesheet copy of either would be a
 * second definition of the one rule DESIGN §13.1 makes a rules constraint.
 */
:root {
  --soot:        #120a04;
  --soot-deep:   #0b0704;
  --iron:        #241a12;
  --iron-hi:     #33251a;
  --brass:       #b98b3f;
  --brass-hi:    #e8c27a;
  --brass-dim:   #6d5228;
  --copper:      #a2571f;
  --bone:        #f2e6cd;
  --bone-dim:    #b7a582;
  --ochre:       #e8891f;
  --edge:        rgba(233, 201, 138, 0.18);
  --panel:       rgba(18, 10, 4, 0.94);
  --tap:         44px;
  --pad:         clamp(10px, 2.4vmin, 18px);
}

/* ═════════════════════════════════════════════════════════ reset and the stage */

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%;
  overflow: hidden;
  background: var(--soot-deep);
  color: var(--bone);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

body {
  display: grid;
  place-items: center;
  /* The safe area is honoured by INSETTING the whole stage, never by cropping the field. */
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}

/*
 * `touch-action: none` is on the CANVAS and nowhere else. The helm is a drag and the browser
 * must not steal it; every screen above the canvas keeps its ordinary scrolling and its ordinary
 * zoom, because taking those away from a player reading a settings list is a bug you only notice
 * on a small screen.
 */
#stage {
  display: block;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  background: var(--soot-deep);
  image-rendering: auto;
  /* The renderer sets width/height in CSS px from its own letterbox fit; this only stops a
   * pathological viewport from pushing the canvas past the screen. */
  max-width: 100%;
  max-height: 100%;
}

/* ═════════════════════════════════════════════════════════ screens */

.screens {
  position: fixed;
  inset: 0;
  display: block;
  pointer-events: none;
}

.screen {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  gap: var(--pad);
  padding: var(--pad);
  overflow-y: auto;
  overflow-x: hidden;
  pointer-events: auto;
  background: radial-gradient(120% 90% at 72% 26%, rgba(232, 137, 31, 0.10), transparent 62%), var(--panel);
  animation: fade-in 180ms ease-out;
}

.screen[hidden] { display: none; }

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

/* Motion is a rules position (DESIGN §9.7) and it reaches the chrome too. The OS preference is
 * honoured here directly; the in-game setting is honoured by the renderer. */
@media (prefers-reduced-motion: reduce) {
  .screen { animation: none; }
  .countdown { animation: none; }
}

.panel,
.title-plate {
  width: min(560px, 100%);
  max-width: 100%;
  padding: calc(var(--pad) * 1.4);
  background: linear-gradient(180deg, var(--iron-hi), var(--iron));
  border: 1px solid var(--brass-dim);
  border-radius: 6px;
  box-shadow: inset 0 1px 0 rgba(232, 194, 122, 0.22), 0 8px 30px rgba(0, 0, 0, 0.55);
}

h1, h2 {
  margin: 0 0 0.4em;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bone);
}

h1 { font-size: clamp(28px, 7vmin, 54px); letter-spacing: 0.22em; }
h2 { font-size: clamp(15px, 3vmin, 21px); color: var(--brass-hi); }

p { margin: 0 0 0.7em; line-height: 1.5; }

.title-strap { color: var(--ochre); letter-spacing: 0.08em; }
.title-note { color: var(--brass); font-size: 12px; opacity: 0.8; }

.fineprint {
  font-size: 11px;
  line-height: 1.6;
  color: var(--brass);
  opacity: 0.75;
}

/* ═════════════════════════════════════════════════════════ controls */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  min-width: var(--tap);
  padding: 0 18px;
  margin: 4px 6px 4px 0;
  font: inherit;
  font-size: 13px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--soot);
  background: linear-gradient(180deg, var(--brass-hi), var(--brass));
  border: 1px solid var(--brass-dim);
  border-radius: 4px;
  cursor: pointer;
  touch-action: manipulation;
}

.btn:hover { filter: brightness(1.08); }
.btn:active { transform: translateY(1px); }

.btn:focus-visible {
  outline: 2px solid var(--bone);
  outline-offset: 2px;
}

.btn-big { font-size: 16px; padding: 0 30px; min-height: 54px; }

.btn-quiet {
  color: var(--brass-hi);
  background: transparent;
  border-color: var(--edge);
}

.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  width: 100%;
}

.row-label {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brass);
}

.chips { display: flex; flex-wrap: wrap; gap: 6px; }

.chip {
  min-height: var(--tap);
  min-width: var(--tap);
  padding: 0 12px;
  font: inherit;
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--brass-hi);
  background: var(--iron);
  border: 1px solid var(--edge);
  border-radius: 3px;
  cursor: pointer;
  touch-action: manipulation;
}

.chip.on {
  color: var(--soot);
  background: var(--brass);
  border-color: var(--brass-hi);
}

.chip:focus-visible { outline: 2px solid var(--bone); outline-offset: 2px; }

/* ═════════════════════════════════════════════════════════ the deck plates */

.deck-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 8px;
  width: min(720px, 100%);
}

.plate {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 4px;
  min-height: 58px;
  padding: 10px 14px;
  font: inherit;
  text-align: left;
  color: var(--bone);
  background: linear-gradient(180deg, var(--iron-hi), var(--iron));
  border: 1px solid var(--brass-dim);
  border-left: 3px solid var(--ochre);
  border-radius: 4px;
  cursor: pointer;
  touch-action: manipulation;
}

.plate:disabled {
  cursor: not-allowed;
  opacity: 0.42;
  border-left-color: var(--brass-dim);
}

.plate-name {
  font-size: 14px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.plate-sub {
  font-size: 11px;
  color: var(--brass);
  letter-spacing: 0.04em;
}

/* ═════════════════════════════════════════════════════════ the ascent */

/*
 * The briefing is the interstitial between Decks (DESIGN §1): the sun ticking down, one line of
 * stencilled Concord type bottom-left with the Deck's name and its depot number. Nothing gloats
 * and nothing is tallied, so this screen has no buttons and no numbers.
 */
.screen-briefing { place-items: end start; background: var(--soot-deep); }

.brief { padding: calc(var(--pad) * 1.5); max-width: 100%; }
.brief-depot { font-size: 11px; letter-spacing: 0.24em; color: var(--brass-dim); margin-bottom: 0.2em; }
.brief-name { font-size: clamp(22px, 6vmin, 40px); color: var(--bone); }
.brief-sun { font-size: 12px; letter-spacing: 0.14em; color: var(--ochre); }

/* ═════════════════════════════════════════════════════════ the pause Governor */

/*
 * The read-only Governor. It carries the same four states the canvas bar does — lit, spendable,
 * maxed, committed — because a player who learns the bar on the HUD must not have to learn a
 * second vocabulary the moment they pause.
 */
.governor {
  list-style: none;
  margin: 0 0 var(--pad);
  padding: 0;
  width: 100%;
  border-top: 1px solid var(--edge);
}

.rung {
  display: grid;
  grid-template-columns: 2ch 1fr auto;
  gap: 10px;
  align-items: center;
  min-height: 34px;
  padding: 0 6px;
  border-bottom: 1px solid var(--edge);
  font-size: 12px;
  color: var(--brass);
}

.rung-n { color: var(--brass-dim); }
.rung-label { letter-spacing: 0.10em; text-transform: uppercase; }
.rung-count { color: var(--bone); opacity: 0.8; }

.rung.lit {
  color: var(--bone);
  background: linear-gradient(90deg, rgba(185, 139, 63, 0.28), transparent);
  border-left: 3px solid var(--brass-hi);
  padding-left: 3px;
}

/* Cross-hatched, exactly as the canvas bar draws it: a maxed rung must be legible as "there is
 * nothing here for you" BEFORE the player spends a cursor on it (§12-R48). */
.rung.maxed {
  opacity: 0.5;
  background-image: repeating-linear-gradient(45deg, transparent 0 4px, var(--edge) 4px 5px);
}

/* ═════════════════════════════════════════════════════════ tallies and settings */

.tally, .settings {
  list-style: none;
  margin: 0 0 var(--pad);
  padding: 0;
  width: 100%;
}

.tally li, .settings li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 34px;
  padding: 4px 6px;
  border-bottom: 1px solid var(--edge);
  font-size: 12px;
  letter-spacing: 0.06em;
}

.tally li span:first-child { color: var(--brass); text-transform: uppercase; }
.tally li span:last-child { color: var(--bone); font-size: 15px; }
.tally-line { font-size: 14px; color: var(--brass-hi); }

.settings li { align-items: center; }
.set-label { color: var(--brass); text-transform: uppercase; }
.set-group { display: flex; flex-wrap: wrap; gap: 4px; }

/* ═════════════════════════════════════════════════════════ overlays */

.countdown {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: clamp(64px, 22vmin, 180px);
  font-weight: 700;
  color: var(--brass-hi);
  text-shadow: 0 0 24px rgba(232, 137, 31, 0.5);
  pointer-events: none;
  z-index: 4;
  animation: none;
}

.countdown[hidden] { display: none; }

.toast {
  position: fixed;
  left: 50%;
  bottom: max(12px, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  max-width: calc(100vw - 24px);
  padding: 10px 16px;
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--bone);
  background: var(--panel);
  border: 1px solid var(--brass-dim);
  border-radius: 4px;
  pointer-events: none;
  z-index: 5;
}

.toast[hidden] { display: none; }

.hint {
  position: fixed;
  left: 50%;
  top: max(12px, env(safe-area-inset-top));
  transform: translateX(-50%);
  width: min(340px, calc(100vw - 24px));
  padding: 14px 16px;
  background: linear-gradient(180deg, var(--iron-hi), var(--iron));
  border: 1px solid var(--brass-dim);
  border-radius: 5px;
  cursor: pointer;
  z-index: 6;
}

.hint[hidden] { display: none; }
.hint .plate-name { display: block; margin-bottom: 6px; }
.hint .plate-sub { display: block; }

.boot-error {
  position: fixed;
  inset: auto 12px 12px 12px;
  padding: 12px 14px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--bone);
  background: var(--copper);
  border-radius: 4px;
  z-index: 9;
}

.boot-error[hidden] { display: none; }

/* ═════════════════════════════════════════════════════════ portrait */

/*
 * In portrait the canvas already carries the letterbox, the controls and the readability floor
 * (DESIGN §8.7) — the renderer positions all three in field coordinates. All this query does is
 * give the chrome room to breathe on a narrow screen. It must never touch the canvas geometry.
 */
@media (orientation: portrait) {
  .deck-list { grid-template-columns: 1fr; }
  .panel, .title-plate { width: 100%; }
  h1 { font-size: clamp(26px, 9vmin, 44px); }
}

@media (max-height: 420px) {
  .screen { place-items: center; }
  .panel, .title-plate { padding: var(--pad); }
  h1 { margin-bottom: 0.2em; }
  .fineprint { display: none; }
}

/* ── the briefing's boss plate ────────────────────────────────────────────────────────────────
 * `contain` rather than `cover`: these are cut-out sprites on transparency with a real silhouette,
 * and cropping one to fill a box is how a boss loses the outline that makes it recognisable when
 * the player meets it ninety seconds later. The whole point of showing it here is the shape.
 * No fixed height in px — it takes its size from the viewport's shorter axis so the same rule
 * serves a 360-tall landscape frame and an 844-tall portrait one. */
.brief-plate {
  width: 100%;
  height: min(38vh, 42vw);
  margin-top: 0.6rem;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  /* Below the reduced-motion floor by construction: it does not move at all. The fade is a fade
   * in opacity over 600ms and never a flash — DESIGN §9.7 caps anything faster. */
  animation: brief-plate-in 600ms ease-out both;
}
@keyframes brief-plate-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .brief-plate { animation: none; } }
