/* ═══════════════════════════════════════════════════════════
   The Long Watch — base layer: reset, tokens, layout, screens
   ═══════════════════════════════════════════════════════════ */

:root {
  --bg-void:      #05070d;
  --bg-deep:      #080b14;
  --panel:        rgba(15, 19, 32, 0.88);
  --panel-solid:  #0f1320;
  --panel-edge:   rgba(140, 165, 220, 0.14);
  --panel-edge-hi:rgba(160, 190, 255, 0.30);

  --ink:          #e9eef8;
  --ink-dim:      #c2ccdf;   /* was #a4b0c8 — body text, now ~9:1 on panels */
  --ink-mute:     #93a0ba;   /* was #6d7a94 — labels, now ~5.5:1 */

  --gold:         #ffc766;
  --gold-deep:    #b8853a;
  --ember:        #ff9d4d;
  --danger:       #ff5f74;
  --frost:        #78dcff;
  --venom:        #a6f06a;
  --storm:        #b389ff;
  --leaf:         #8fd67a;

  --radius:   14px;
  --radius-s: 10px;

  --shadow-lift: 0 10px 30px rgba(0,0,0,.55);
  --glow-gold:   0 0 24px rgba(255,199,102,.35);

  --font-display: 'Cinzel', 'Georgia', serif;
  --font-ui: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --dock-w: 344px;
  --topbar-h: 56px;

  /* Safe areas as variables, not raw env(), so the test harness can inject
     standalone-PWA values. In a browser these resolve to env() as normal. */
  --sat: env(safe-area-inset-top, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  --sal: env(safe-area-inset-left, 0px);
  --sar: env(safe-area-inset-right, 0px);

  /* Real viewport height, written by main.js from visualViewport. dvh/vh are
     unreliable in iOS standalone; a measured pixel value never is. */
  --app-h: 100dvh;

  /* ── The stylesheet's build number ──────────────────────
     index.html carries the same number in <meta name="lw-css-build">, and
     main.js compares them at boot. If they disagree the browser is pairing
     this page's markup with a stylesheet out of a stale cache, and it
     re-fetches the CSS rather than rendering a pile.

     This is not paranoia. It happened: index.html and the JS revalidated over
     a bad connection, hud.css did not, and the Keep drew its drawer inline
     with no background — the tabs painted over the Watch Tree, and the one
     button the screen exists for sat on top of the list. Nothing in the page
     linked the markup to the stylesheet, so nothing could notice.

     BUMP THIS whenever a CSS change needs markup or JS that ships with it.
     tools/page.mjs fails if the two numbers ever drift apart. */
  --css-build: 2;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  height: 100%;
  overflow: hidden;
  background: var(--bg-void);
  color: var(--ink);
  font-family: var(--font-ui);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
}

body { touch-action: manipulation; }

button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
h1, h2, h3 { font-family: var(--font-display); font-weight: 700; letter-spacing: .02em; }

.hidden { display: none !important; }

/* ── App shell ─────────────────────────────────────────── */

#app {
  position: relative;
  display: grid;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  height: var(--app-h);
  max-height: var(--app-h);
  /* Nothing may ever push out of the viewport. */
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 0%, #10162a 0%, #070a12 55%, #04060b 100%);
}

/* Ambient starfield behind everything */
#app::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    radial-gradient(1px 1px at 12% 22%, rgba(190,215,255,.55), transparent),
    radial-gradient(1px 1px at 78% 12%, rgba(190,215,255,.40), transparent),
    radial-gradient(1px 1px at 45% 68%, rgba(190,215,255,.30), transparent),
    radial-gradient(1.5px 1.5px at 88% 74%, rgba(255,220,180,.35), transparent),
    radial-gradient(1px 1px at 30% 88%, rgba(190,215,255,.35), transparent),
    radial-gradient(1px 1px at 62% 40%, rgba(190,215,255,.25), transparent);
  opacity: .8;
  z-index: 0;
}

/* ── Playfield ─────────────────────────────────────────── */

#stage {
  grid-area: stage;
  position: relative;
  display: grid;
  place-items: center;
  min-width: 0;
  min-height: 0;
  padding: 10px;
  z-index: 1;
}

#board {
  position: relative;
  line-height: 0;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow:
    0 0 0 1px rgba(150,175,225,.15),
    0 0 0 6px rgba(10,14,24,.75),
    0 24px 60px rgba(0,0,0,.7),
    0 0 90px rgba(60,90,170,.10);
}

#game {
  display: block;
  touch-action: none;
  cursor: crosshair;
  background: #070a11;
}

#board-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  line-height: 1.4;
}

/* Vignette on the board itself */
#board::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(115% 115% at 50% 45%, transparent 52%, rgba(2,4,9,.72) 100%);
  border-radius: var(--radius);
}

/* ── Screens (title / end / manual) ────────────────────── */

.screen {
  position: absolute;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  background: radial-gradient(90% 70% at 50% 40%, rgba(10,14,26,.86), rgba(4,6,12,.97));
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  animation: fadeIn .4s ease both;
  overflow: hidden;
}

#title-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: .85;
}

.screen-inner {
  position: relative;
  z-index: 2;
  width: min(620px, 92vw);
  max-width: 100%;
  overflow-x: hidden;
  max-height: calc(var(--app-h) - 24px);
  overflow-y: auto;
  text-align: center;
  /* Sides included: in landscape a notched phone insets left and right, and
     every screen in the game used to run underneath both. */
  padding: calc(24px + var(--sat)) calc(20px + var(--sar))
           calc(24px + var(--sab))  calc(20px + var(--sal));
  animation: riseIn .55s cubic-bezier(.16,1,.3,1) both;
}

.title-sigil { width: 92px; height: 92px; margin-bottom: 4px; }
.sig-ring  { fill: none; stroke: rgba(255,199,102,.28); stroke-width: 1.2; }
.sig-ring2 { fill: none; stroke: rgba(255,199,102,.16); stroke-width: .8; stroke-dasharray: 4 7; animation: spin 44s linear infinite; transform-origin: 60px 60px; }
.sig-star  { fill: var(--gold); filter: drop-shadow(0 0 14px rgba(255,180,80,.75)); animation: pulseGlow 3.6s ease-in-out infinite; }

.game-title {
  font-size: clamp(2.2rem, 8vw, 3.9rem);
  line-height: 1.02;
  letter-spacing: .04em;
  background: linear-gradient(180deg, #fff6e2 0%, var(--gold) 48%, #a86c24 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow: 0 0 44px rgba(255,170,70,.28);
  margin-bottom: .35rem;
}
.game-title.small { font-size: clamp(1.6rem, 5vw, 2.3rem); }

.tagline {
  color: var(--ink-dim);
  font-size: clamp(.9rem, 2.4vw, 1.05rem);
  max-width: 42ch;
  margin: 0 auto 1.6rem;
  line-height: 1.6;
}

/* Difficulty picker */
.difficulty-select {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 9px;
  margin-bottom: 1.5rem;
  text-align: left;
}
/* minmax(0,·) is load-bearing: with the default `auto` minimum, "Nightbound"
   refuses to shrink and pushes the third card off the screen. */
.diff-card {
  padding: clamp(8px, 2.4vw, 12px) clamp(6px, 2vw, 12px) clamp(9px, 2.4vw, 13px);
  min-width: 0;
  border-radius: var(--radius-s);
  border: 1px solid var(--panel-edge);
  background: rgba(12,16,28,.72);
  transition: border-color .18s, background .18s, transform .18s;
}
.diff-card:hover { border-color: var(--panel-edge-hi); transform: translateY(-2px); }
.diff-card.on {
  border-color: rgba(255,199,102,.65);
  background: linear-gradient(180deg, rgba(255,199,102,.14), rgba(255,199,102,.04));
  box-shadow: inset 0 0 22px rgba(255,180,80,.10);
}
.diff-name {
  font-family: var(--font-display);
  font-size: clamp(.72rem, 3.2vw, .98rem);
  color: var(--gold); margin-bottom: 3px;
  overflow-wrap: anywhere;
}
.diff-desc {
  font-size: clamp(.62rem, 2.4vw, .73rem);
  color: var(--ink-mute); line-height: 1.4;
  overflow-wrap: anywhere;
}
.diff-prose { display: block; margin-bottom: 2px; }
.diff-nums { display: block; color: var(--ink-dim); }

.title-meta {
  margin-top: 1.15rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  font-size: .8rem;
  color: var(--ink-mute);
  flex-wrap: wrap;
}
.link-btn { color: var(--ink-dim); text-decoration: underline; text-underline-offset: 3px; opacity: .8; }
.link-btn:hover { color: var(--gold); opacity: 1; }

/* End screen */
.end-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
  gap: 9px;
  margin: 1.4rem 0 1.6rem;
}
.end-stat {
  padding: 12px 8px;
  border-radius: var(--radius-s);
  background: rgba(12,16,28,.7);
  border: 1px solid var(--panel-edge);
}
.end-stat-val { font-family: var(--font-display); font-size: 1.5rem; color: var(--gold); display: block; }
.end-stat-lbl { font-size: .68rem; text-transform: uppercase; letter-spacing: .13em; color: var(--ink-mute); }
.end-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

/* Manual */
.manual { text-align: left; width: min(700px, 94vw); }
.manual h2 {
  font-size: 1rem; color: var(--gold); margin: 1.5rem 0 .5rem;
  text-transform: uppercase; letter-spacing: .14em;
}
.manual h2:first-of-type { margin-top: .8rem; }
.manual p, .manual li { color: var(--ink-dim); font-size: .87rem; line-height: 1.65; }
.manual ul { padding-left: 1.1rem; }
.manual li { margin-bottom: .35rem; }
.manual li b { color: var(--ink); font-weight: 600; }
.manual .kbd {
  display: inline-block; padding: 1px 6px; margin: 0 2px;
  border-radius: 5px; background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.14);
  font-size: .78em; font-family: ui-monospace, monospace; color: var(--ink);
}
.manual .primary-btn { margin-top: 1.8rem; width: 100%; }

/* ── Animations ────────────────────────────────────────── */

@keyframes fadeIn { from { opacity: 0 } to { opacity: 1 } }
@keyframes riseIn { from { opacity: 0; transform: translateY(22px) } to { opacity: 1; transform: none } }
@keyframes spin { to { transform: rotate(360deg) } }
@keyframes pulseGlow {
  0%, 100% { opacity: .9; filter: drop-shadow(0 0 12px rgba(255,180,80,.6)) }
  50%      { opacity: 1;  filter: drop-shadow(0 0 26px rgba(255,200,110,.95)) }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}


/* ── Short viewports: the title screen must never push the start button
      below the fold. Landscape phones and browser-chrome portrait both
      land here, so it is driven by height, not by device. ─────────────── */

@media (max-height: 620px) {
  .title-sigil { width: 58px; height: 58px; margin-bottom: 0; }
  .game-title { font-size: clamp(1.5rem, 6vw, 2.4rem); margin-bottom: .2rem; }
  .tagline { font-size: .8rem; margin-bottom: .85rem; line-height: 1.45; }
  .difficulty-select { gap: 6px; margin-bottom: .85rem; }
  .diff-prose { display: none; }
  .title-meta { margin-top: .7rem; font-size: .72rem; gap: 12px; }
  .primary-btn.big { padding: 12px 22px; font-size: .92rem; min-width: 180px; }
  .screen-inner { padding-top: calc(12px + var(--sat)); padding-bottom: calc(12px + var(--sab)); }
  .end-stats { gap: 6px; margin: .9rem 0 1rem; }
  .end-stat { padding: 8px 6px; }
  .end-stat-val { font-size: 1.15rem; }
  .manual p, .manual li { font-size: .8rem; line-height: 1.5; }
}

@media (max-height: 460px) {
  .title-sigil { display: none; }
  .tagline { display: none; }
  .game-title { font-size: clamp(1.3rem, 5vw, 1.9rem); }
  .difficulty-select { margin-bottom: .7rem; }
  .diff-name { font-size: clamp(.68rem, 2.6vw, .82rem); }
  .end-stats { grid-template-columns: repeat(auto-fit, minmax(88px, 1fr)); }
}

/* ── The title screen, composed around the art ──────────────
   The painting carries a lit tower in its upper two thirds and
   deliberately empty dark ground in the lower third. So the
   words live DOWN THERE, on the empty part, instead of sitting
   across the fire and fighting it for the same space.

   The sigil moved into the wordmark rather than floating above
   it: it is the same mark as the favicon, it reads as a logo
   beside the words, and it gives back the vertical space the
   art wants. ── */

#screen-title { place-items: end center; }
#screen-title .screen-inner {
  padding-bottom: calc(30px + var(--sab));
  /* Never taller than the screen: .screen does not scroll, and a panel that
     overflows a place-items grid puts its top out of reach. */
  max-height: calc(var(--app-h) - 16px);
}

.game-title {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .34em;
}
/* The gradient fill is on the text; the sigil must not inherit the clip. */
.game-title > span {
  background: inherit;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.title-sigil {
  width: .82em; height: .82em;
  margin: 0;
  flex: none;
  /* The SVG carries its own colour — keep it clear of the text gradient. */
  -webkit-background-clip: border-box;
  background-clip: border-box;
}

/* A soft floor under the words so they never sit on paint. */
/* The scrim carries ALL the readability now that the painting runs at full
   strength. Deeper than before, and it starts higher, so the words sit on
   their own dark ground rather than on the tower. */
#screen-title.has-art .screen-inner {
  background: linear-gradient(180deg, transparent, rgba(5,7,13,.72) 18%, rgba(5,7,13,.93) 46%, rgba(5,7,13,.97) 100%);
  border-radius: 22px 22px 0 0;
  box-shadow: 0 -30px 60px rgba(5,7,13,.6);
}

@media (max-width: 560px) {
  #screen-title .screen-inner { padding-bottom: calc(16px + var(--sab)); }
  .title-sigil { width: .8em; height: .8em; }
}
