/* UI per review/UI_SPEC.md: one serif, two inks, one flat olive-black surface, square corners, nothing drawn. */
:root {
  color-scheme: dark;
  --font: "Newsreader", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  --ground: #121208;
  --ground-step: #2b2c14;
  --ground-hover: #3a3b1b;
  --ink: #e4ece2;
  --muted: #a3a98f;
  --label: #8a9078;         /* group labels in the controls: 5.7:1 on the ground */
  --focus: #bee1d3;
  --edge: 28px;
  --pad: 32px;
  --panel-w: 440px;
  --t-body: 17px; --t-small: 14px; --t-head: 28px; --title-size: 40px;
  --ease: cubic-bezier(.2,.7,.2,1);
}
@media (max-width: 600px) {
  :root { --edge: 16px; --pad: 20px; --t-body: 16px; --t-small: 13px; --t-head: 24px; --title-size: 26px; }
}

* { box-sizing: border-box; }
html, body {
  margin: 0; height: 100%; background: var(--ground); color: var(--ink);
  font-family: var(--font); font-optical-sizing: auto; font-kerning: normal; text-rendering: optimizeLegibility;
  font-size: var(--t-body); line-height: 1.45; overflow: hidden; -webkit-font-smoothing: antialiased;
}
button { font: inherit; color: inherit; }
a { color: var(--ink); }

#scene { position: fixed; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }
#scene.is-hover { cursor: pointer; }
#scene:focus { outline: none; }

/* Loading: dark screen, slow pulse */
.loading {
  position: fixed; inset: 0; z-index: 40; display: grid; place-content: center; gap: 24px; text-align: center;
  background: var(--ground); transition: opacity 900ms var(--ease);
}
.loading.is-done { opacity: 0; pointer-events: none; }
.loading-pulse { width: 8px; height: 8px; background: var(--ink); margin: 0 auto; animation: pulse 3s ease-in-out infinite; }
.loading-text { margin: 0; color: var(--muted); font-size: var(--t-body); }
@keyframes pulse { 0%, 100% { opacity: 0.2; } 50% { opacity: 1; } }

/* Title: large and centred on first load, then settles top-left as the one h1 */
.title {
  position: fixed; left: var(--edge); bottom: var(--edge); margin: 0 0 0 -0.04em; z-index: 20;
  font-size: var(--title-size); font-weight: 400; line-height: 1; letter-spacing: -0.015em;
  color: var(--ink); opacity: 0; white-space: nowrap; pointer-events: none;
  text-shadow: 0 1px 2px rgba(0,0,0,0.85), 0 0 18px rgba(0,0,0,0.7);   /* legibility scrim over bright tiles, intro and settled alike */
  transition: opacity 600ms var(--ease);
}
.title.is-visible { opacity: 0.92; }
.title.is-intro {
  left: 50%; bottom: 50%; transform: translate(-50%, 50%); font-size: clamp(40px, 6.5vw, 96px); white-space: normal; text-align: center;
  width: min(92vw, 14ch); transition: opacity 800ms var(--ease);
}
.title.is-intro.is-visible { opacity: 1; }
.title:not(.is-intro) { bottom: auto; top: var(--edge); text-shadow: 0 1px 2px rgba(0,0,0,0.85), 0 0 18px rgba(0,0,0,0.7); }   /* settles top-left; the shadow is a legibility scrim over bright tiles, not decoration */

/* Controls strip: one quiet bar on the room's ground, left to right Play, Random, Credits; no rules, boxes or
   badges; Play and Random keep the step ground. The motion is not a control. */
.controls {
  position: fixed; left: var(--edge); right: var(--edge); bottom: var(--edge); z-index: 20;
  display: flex; align-items: flex-end; gap: 6px; opacity: 0; transition: opacity 600ms var(--ease), right 320ms var(--ease);
}
.controls.is-visible { opacity: 1; }
/* one dark ground, left to right: Play, Random, Credits */
.bar { display: flex; align-items: center; gap: 22px; background: var(--ground); padding: 0 18px 0 0; min-height: 44px; }
.bar .btn + .btn { margin-left: -16px; }   /* the two blocks sit together at the left edge */
.group-label { color: var(--label); font-size: var(--t-small); white-space: nowrap; }   /* a step quieter than the options, so it names the row rather than joining it */
.controls .plain { background: var(--ground-step); padding: 0 16px; min-height: 44px; }
.controls .plain:hover { background: var(--ground-hover); }
body.panel-open .controls { right: calc(var(--panel-w) + var(--edge)); }
/* ?poster=1: a bare render; every DOM layer is hidden and the cursor too */
body.poster .title, body.poster .controls, body.poster .caption, body.poster .hint, body.poster .labels, body.poster .panel, body.poster .scrim, body.poster #loading.is-done { display: none !important; }
body.poster, body.poster canvas { cursor: none !important; }
/* the game layer is open: the room's chrome steps aside (the dimmed room still flows behind) */
body.in-game .title, body.in-game .controls, body.in-game .caption, body.in-game .hint, body.in-game .labels { display: none; }

/* Pigment: faint domain labels over the largest patches (projected each frame) */
.labels { position: fixed; inset: 0; pointer-events: none; z-index: 5; }
.patch-label { position: absolute; left: 0; top: 0; margin: -0.6em 0 0 -1em; font-size: var(--t-small); color: var(--ink); opacity: 0; transition: opacity 700ms var(--ease); text-shadow: 0 1px 2px rgba(0,0,0,0.85), 0 0 14px rgba(0,0,0,0.7); white-space: nowrap; }
.patch-label.is-on { opacity: 0.72; }

/* hover caption: the tile's title near the cursor after a short dwell */
.caption { position: fixed; left: 0; top: 0; z-index: 15; pointer-events: none; max-width: 320px; padding: 8px 12px; background: var(--ground-step); color: var(--ink); font-size: var(--t-small); line-height: 1.3; opacity: 0; transition: opacity 180ms var(--ease); }
.caption.is-on { opacity: 1; }
.caption[hidden] { display: none; }

/* the one-line keyboard hint on first load */
.hint { position: fixed; left: 50%; bottom: calc(var(--edge) + 60px); transform: translateX(-50%); z-index: 15; margin: 0; padding: 10px 16px; background: var(--ground-step); color: var(--muted); font-size: var(--t-small); white-space: nowrap; opacity: 0; transition: opacity 900ms var(--ease); pointer-events: none; }
.hint.is-on { opacity: 1; }
.hint[hidden] { display: none; }
@media (max-width: 600px) { .hint { display: none; } }

/* the breathing dot: beats at the room's current tempo, driven from the energy model */
.beat { display: inline-block; font-size: 1.3em; line-height: 0.6; margin-left: 0.28em; vertical-align: 0.02em; color: var(--ink); opacity: 0.7; transform-origin: 50% 50%; }
.beat::before { content: '\2022'; }   /* a glyph rather than a box so the title's legibility shadow covers it too */
.title.is-intro .beat { display: none; }

@media (max-width: 600px) {
  .controls { left: var(--edge); right: var(--edge); bottom: calc(var(--edge) + env(safe-area-inset-bottom)); gap: 8px; }
  /* the strip holds all three within thumb reach: Play and Random as blocks, Credits as a plain word */
  .bar { width: 100%; gap: 12px; padding: 0 12px 0 0; background: none; }
  .bar .btn + .btn { margin-left: -4px; }
  .controls .btn-play, .controls .btn-random { flex: 1 1 0; min-height: 48px; min-width: 0; padding-left: 12px; padding-right: 12px; }
  .controls .plain { min-height: 48px; padding: 0 12px; }
  body.panel-open .controls { display: none; }
}

.btn {
  font: inherit; font-size: var(--t-body); font-weight: 500; line-height: 1; letter-spacing: 0.01em;
  color: var(--ink); background: var(--ground-step); border: 0; border-radius: 0; padding: 12px 20px; cursor: pointer;
  transition: background 120ms;
}
.btn:hover { background: var(--ground-hover); }
.btn:active { transform: translateY(1px); }
.btn-random { min-height: 44px; min-width: 112px; }

.plain {
  font: inherit; font-size: var(--t-body); font-weight: 400; line-height: 1; color: var(--ink);
  background: none; border: 0; padding: 12px 0; cursor: pointer; min-height: 41px;
  text-decoration: underline; text-underline-offset: 0.16em; text-decoration-thickness: 1px; text-decoration-color: var(--muted);
}
.plain:hover { text-decoration-color: var(--ink); }
.btn:focus-visible, .plain:focus-visible, a:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }

/* Scrim catches clicks outside the panel */
.scrim { position: fixed; inset: 0; z-index: 24; background: transparent; }

/* Detail panel: a flat column of ground, flush right, full height */
.panel {
  position: fixed; top: 0; right: 0; bottom: 0; width: var(--panel-w); background: var(--ground); z-index: 25;
  padding: var(--pad); overflow-y: auto; display: flex; flex-direction: column; scrollbar-width: thin;
  transform: translateX(18px); opacity: 0; transition: transform 320ms var(--ease), opacity 320ms;
}
.panel[hidden] { display: none; }
.panel.is-open { transform: none; opacity: 1; }
.panel.is-closing { transition-duration: 200ms; }
.panel .close { position: absolute; top: calc(var(--pad) - 12px); right: var(--pad); }
.panel-body { display: flex; flex-direction: column; flex: 1 0 auto; }
.panel .tile { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; margin-top: 44px; background: #000; }
.panel h2 { font-size: var(--t-head); font-weight: 400; line-height: 1.12; letter-spacing: -0.01em; margin: 24px 0 0; text-wrap: balance; }
.panel h2 { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }   /* a long title stops after three lines */
/* The written piece: four sizes only (28 heading, 17 text, 14 small); the text comes from data/text.json */
.panel p:empty { display: none; }
.panel .makeline { margin: 12px 0 0; color: var(--muted); line-height: 1.4; }
.panel .hook { margin: 26px 0 0; font-weight: 500; line-height: 1.35; color: var(--ink); text-wrap: pretty; }
.panel .explanation { margin: 18px 0 0; font-size: var(--t-body); line-height: 1.5; max-width: 62ch; color: var(--ink); text-wrap: pretty; }
.panel .aside { margin: 18px 0 0; font-size: var(--t-small); line-height: 1.45; max-width: 62ch; color: var(--ink); text-wrap: pretty; }
.panel .licence { margin: 28px 0 0; font-size: var(--t-small); line-height: 1.45; color: var(--muted); }
.panel .licence a { color: var(--ink); text-decoration: underline; text-underline-offset: 0.16em; text-decoration-thickness: 1px; text-decoration-color: var(--muted); margin-right: 0.6em; white-space: nowrap; }
.panel .licence a[hidden] { display: none; }
.panel .licence a:hover { text-decoration-color: var(--ink); }
.panel .list { margin: 32px 0 0; padding: 0; list-style: none; font-size: var(--t-small); line-height: 1.45; }
.panel .list li { margin: 0 0 12px; }
.panel .list .t { color: var(--ink); display: block; }
.panel .list .c { color: var(--muted); }
.panel .list a { color: var(--ink); text-decoration: underline; text-underline-offset: 0.16em; text-decoration-thickness: 1px; text-decoration-color: var(--muted); }
.credits h2 { margin-top: 44px; }

/* Phone: the detail panel becomes a bottom sheet so the tile stays visible above it */
@media (max-width: 600px) {
  .panel { width: 100%; top: auto; max-height: 52vh; transform: translateY(18px); padding-bottom: calc(var(--pad) + env(safe-area-inset-bottom)); }
  .panel.is-open { transform: none; }
  .panel .tile { display: none; }
  .panel h2 { margin-top: 36px; -webkit-line-clamp: 2; }   /* two lines at most at 390 px, then an ellipsis */
  .panel .hook { margin-top: 20px; }
  .credits { top: 0; max-height: none; }
  .credits h2 { margin-top: 40px; }
  .btn-random { min-height: 48px; padding: 14px 24px; }
}

@media (prefers-reduced-motion: reduce) {
  .panel, .title, .controls, .btn-random { transition: none; }
  .loading-pulse { animation-duration: 6s; }
}
