/*
 * Base stylesheet for the visual-novel engine.
 *
 * The STRUCTURE below (title screen, plate frame, text box, choices, minigame
 * canvas, ending card, reset control) is the reusable part — it matches the
 * DOM in index.html and the states engine.js drives. Leave the selectors and
 * layout alone unless you're changing the actual UI shape.
 *
 * Everything under "PROJECT PALETTE" and "SPEAKER REGISTERS" below is *not*
 * generic — it is where THE UNATTENDED's style bible (design-catalog.md §1
 * and §2) becomes CSS. Five speakers are wired below — thought, bandaged,
 * minstrels, keeper, crowd — plus `data-speaker="none"`, which the engine
 * uses for the narrator/caption register (see docs/03-WRITING-VOICE.md).
 */

:root {
  /* ─── PROJECT PALETTE — THE UNATTENDED ────────────────────────────────────
     The measured ramp from design-catalog.md §2, derived by k-means from the
     source images rather than by eye. The world is a warm-earth
     near-monochrome: six values from bone to pitch, and two accents that
     between them cover under 2% of any plate.

     The chrome is parchment, not the pitch of the plates themselves. The
     plates are very dark and very dense; framing them in the reference
     sheets' own paper reads as a painted panel hung on a wall, and keeps the
     UI from competing with the art for the same blacks. */
  --paper-hi:   #EFE7D3;  /* parchment, lit */
  --paper:      #E2D8C0;  /* parchment */
  --paper-lo:   #CFC3A6;
  --drab-lt:    #B2A98F;  /* bone   — lightest value in the world */
  --grey-mid:   #8B7D65;  /* dust */
  --drab:       #6A5B46;  /* clay */
  --slate:      #453C2E;  /* umber */
  --shadow:     #37301F;
  --deep:       #2C2519;
  --mass:       #241F16;  /* deep umber */
  --ink:        #0E0C08;  /* pitch */

  /* Same single-role discipline as the plates, carried into the interface. */
  --accent-a:   #6B3622;  /* OXIDE RED — the marks the town makes about itself.
                             In the UI: anything the player can act on. */
  --accent-b:   #2F3A31;  /* VERDIGRIS — the corruption. In the UI: nothing.
                             It is reserved, and its absence is the point. */

  --font-a: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  --font-b: Georgia, "Iowan Old Style", "Palatino Linotype", Palatino, serif;

  --measure: 68ch;
}

* { box-sizing: border-box; }

/* An ID selector outranks the UA stylesheet's `[hidden] { display: none }`, so
   #minigame/#choices would paint even while hidden. Keep this above them. */
[hidden] { display: none !important; }

html, body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-b);
  display: grid;
  place-items: center;
  padding: clamp(0.75rem, 2vw, 2rem);
  /* Optional paper-grain texture, inline SVG, no external asset. Drop it if
     your style bible isn't paper-and-ink. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.06'/%3E%3C/svg%3E");
}

#app {
  width: min(105ch, 100%);
  display: flex;
  flex-direction: column;
  gap: clamp(0.75rem, 1.5vw, 1.25rem);
}

/* ─── Title ─────────────────────────────────────────────────────────────── */

#title {
  width: min(105ch, 100%);
  aspect-ratio: 3 / 2;  /* match this to your plate model's native output ratio, see docs/02 */
  position: relative;
  border: 1px solid var(--ink);
  outline: 1px solid var(--ink);
  outline-offset: 3px;
  overflow: hidden;
  background-color: var(--paper-lo);
  background-image:
    linear-gradient(
      100deg,
      color-mix(in srgb, var(--paper) 94%, transparent) 0 34%,
      color-mix(in srgb, var(--paper) 70%, transparent) 46%,
      color-mix(in srgb, var(--paper) 8%, transparent) 68%
    ),
    url("../assets/plates/plate_street_wake.png");
  background-size: cover, cover;
  background-position: center, center;
  display: flex;
  align-items: center;
}

#title-card {
  padding: clamp(1.25rem, 4vw, 3.25rem);
  max-width: 46ch;
}

.title-kicker {
  font-family: var(--font-a);
  font-size: 0.64rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--drab);
  margin: 0 0 0.5rem;
}

#title h1 {
  font-family: var(--font-a);
  font-weight: 400;
  font-size: clamp(1.6rem, 5.2vw, 3.2rem);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  margin: 0;
  line-height: 1;
  white-space: nowrap; /* if your title can wrap badly mid-word, add a soft-hyphen or shrink the clamp instead */
}

.title-sub {
  font-family: var(--font-a);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  color: var(--slate);
  margin: 0.7rem 0 1.5rem;
}

#title-status {
  margin: 0 0 1.75rem;
  border-top: 1px solid var(--drab-lt);
  font-family: var(--font-a);
  font-size: 0.66rem;
  letter-spacing: 0.08em;
}
#title-status > div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.38rem 0;
  border-bottom: 1px solid var(--drab-lt);
}
#title-status dt { color: var(--drab); text-transform: uppercase; }
#title-status dd {
  margin: 0;
  color: var(--slate);
  text-transform: uppercase;
}
/* Let the last status row carry weight if it's your hook line (SEKTOR-7 used
   this for "Occupancy: zero" — the line the story's first turn answers). */
#title-status > div:last-child dt,
#title-status > div:last-child dd { color: var(--ink); }

#title-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
}

#title-actions button {
  font-family: var(--font-a);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--paper-hi);
  border: 1px solid var(--ink);
  padding: 0.72rem 1.3rem;
  cursor: pointer;
  transition: background 100ms linear, box-shadow 100ms linear;
}
#title-actions button:hover,
#title-actions button:focus-visible {
  background: var(--paper-lo);
  outline: none;
  box-shadow: inset 3px 0 0 var(--accent-a);
}
#title-actions #start { border-color: var(--slate); color: var(--slate); }

@media (max-width: 560px) {
  #title {
    aspect-ratio: auto;
    min-height: 30rem;
    background-image:
      linear-gradient(
        180deg,
        color-mix(in srgb, var(--paper) 92%, transparent) 0 62%,
        color-mix(in srgb, var(--paper) 30%, transparent) 100%
      ),
      url("../assets/plates/plate_street_wake.png");
    background-position: center, center bottom;
  }
  #title-card { max-width: none; }
}

/* ─── The plate ─────────────────────────────────────────────────────────── */

#plate {
  position: relative;
  margin: 0;
  /* MEASURED, not assumed. `.env` asked gpt-image-2 for 16:9 and it returned
     1536x1024 = 3:2 every time. At 16:9 `object-fit: cover` would crop ~13%
     off the top and bottom of every plate — which in a first-person game
     means losing the sky and his own hands at the lower frame edge, i.e.
     exactly the two things the compositions are built around. See
     docs/02-IMAGE-CONSISTENCY.md and design-catalog.md §8. */
  aspect-ratio: 3 / 2;
  background: var(--paper-lo);
  border: 1px solid var(--ink);
  outline: 1px solid var(--ink);
  outline-offset: 3px;
  overflow: hidden;
}

#plate-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
#plate-img:not([src]), #plate-img[src=""] { display: none; }

#plate-placeholder {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 0.6rem;
  font-family: var(--font-a);
  background:
    repeating-linear-gradient(
      45deg,
      transparent 0 11px,
      color-mix(in srgb, var(--drab-lt) 55%, transparent) 11px 12px
    );
}

.ph-label {
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--drab);
}

.ph-id {
  font-size: clamp(0.85rem, 2vw, 1.15rem);
  letter-spacing: 0.06em;
  color: var(--slate);
  border: 1px dashed var(--grey-mid);
  background: var(--paper);
  padding: 0.45rem 0.9rem;
}

#plate-caption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  font-family: var(--font-a);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--drab);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  border-top: 1px solid var(--drab-lt);
  padding: 0.3rem 0.6rem;
  justify-content: space-between;

  /* engine.js writes the raw plate id into this strip. Useful scaffolding
     while building — you can see at a glance which asset a node points at —
     and pure noise in a finished game: a caption reading
     PLATE_TABERNA_MIRROR_FRAGMENTS across the bottom of a painting. Hidden
     here rather than stripped out of engine.js, so the engine stays generic.
     Set back to `flex` to bring it back while working on the art. */
  display: none;
}

/* ─── The text box ──────────────────────────────────────────────────────── */

#box {
  border: 1px solid var(--ink);
  background: var(--paper-hi);
  padding: clamp(0.9rem, 2vw, 1.4rem);
  min-height: 8.5rem;
  position: relative;
  cursor: pointer;
}

#speaker {
  font-family: var(--font-a);
  font-size: 0.64rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--accent-a);
  margin-bottom: 0.55rem;
  min-height: 0.9rem;
}
/* A speaker with no visual label (e.g. an omnipresent/environmental voice) —
   see engine.js SPEAKER_LABEL. Delete this rule if every speaker gets a label. */
#box[data-speaker="none"] #speaker { visibility: hidden; }

#text {
  margin: 0;
  max-width: var(--measure);
  font-size: clamp(1rem, 1.15vw + 0.72rem, 1.2rem);
  line-height: 1.65;
  white-space: pre-wrap;
}

/* ── Speaker registers — one visual register per speaker, per docs/03. ──
   Five voices plus the narrator. Each register in design-catalog.md §1 gets a
   typographic counterpart here, so the player can tell who is speaking before
   reading a word — the label is confirmation, not the signal. */

/* The protagonist's interior voice. The story's default state: plain serif,
   full ink, no label at all. It is not announced because it is not addressed
   to anyone. */
#box[data-speaker="thought"] #text {
  font-family: var(--font-b);
  color: var(--ink);
}
#box[data-speaker="thought"] #speaker { visibility: hidden; }

/* The Bandaged Man. Loose tracking and extra leading: the line arrives slowly
   on the page the way it arrives slowly out of him (engine.js gives him the
   slowest typewriter speed in the game, 46ms/char). */
#box[data-speaker="bandaged"] #text {
  font-family: var(--font-b);
  color: var(--mass);
  letter-spacing: 0.035em;
  line-height: 1.85;
}

/* The minstrels speak only in verse — set it as verse: hanging indent, ranged
   left, italic. story.js writes their couplets with real newlines and #text is
   `white-space: pre-wrap`, so the line breaks are theirs, not the browser's. */
#box[data-speaker="minstrels"] #text {
  font-family: var(--font-b);
  font-style: italic;
  color: var(--ink);
  padding-left: 1.4rem;
  border-left: 1px solid var(--drab-lt);
  line-height: 1.55;
}

/* The Keeper: brisk, unbothered, faster than everyone. Tight and plain. */
#box[data-speaker="keeper"] #text {
  font-family: var(--font-b);
  color: var(--slate);
  letter-spacing: -0.005em;
}

/* The street speaking as a mass — overheard, not addressed to him. Mono and
   spaced out so it reads as fragments crossing the frame rather than speech. */
#box[data-speaker="crowd"] #text {
  font-family: var(--font-a);
  font-size: clamp(0.82rem, 0.9vw + 0.6rem, 0.95rem);
  color: var(--drab);
  letter-spacing: 0.06em;
}

/* Narrator / caption register (speaker: null in story.js) — third person,
   present tense, camera-only, and the one voice that measures. Kept visually
   coldest: italic, dropped back to umber, never full ink. */
#box[data-speaker="none"] #text {
  font-style: italic;
  color: var(--slate);
}

#advance {
  position: absolute;
  right: 0.9rem;
  bottom: 0.7rem;
  width: 0.5rem;
  height: 0.5rem;
  background: var(--ink);
  opacity: 0;
  transition: opacity 120ms linear;
}
#box[data-done="true"] #advance {
  opacity: 1;
  animation: blink 1.1s steps(1, end) infinite;
}
@keyframes blink { 50% { opacity: 0.15; } }

/* ─── Choices ───────────────────────────────────────────────────────────── */

#choices {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

#choices button {
  font-family: var(--font-a);
  font-size: clamp(0.8rem, 0.75vw + 0.62rem, 0.92rem);
  line-height: 1.55;
  text-align: left;
  color: var(--ink);
  background: var(--paper-hi);
  border: 1px solid var(--slate);
  padding: 0.75rem 0.95rem;
  cursor: pointer;
  transition: background 100ms linear, border-color 100ms linear;
}

#choices button:hover,
#choices button:focus-visible {
  background: var(--paper-lo);
  border-color: var(--ink);
  outline: none;
  box-shadow: inset 3px 0 0 var(--accent-a);
}

/* ─── Minigame ──────────────────────────────────────────────────────────── */

#minigame {
  width: 100%;
  aspect-ratio: 16 / 7;
  border: 1px solid var(--ink);
  background: var(--paper-hi);
  display: block;
  cursor: pointer;
  margin-bottom: 2.5rem;  /* keep the canvas off the page edge */
}

/* ─── Ending ────────────────────────────────────────────────────────────── */

#ending {
  border: 1px solid var(--ink);
  outline: 1px solid var(--ink);
  outline-offset: 3px;
  background: var(--paper-hi);
  padding: clamp(1.5rem, 4vw, 2.75rem);
  text-align: center;
}

.ending-kicker {
  font-family: var(--font-a);
  font-size: 0.64rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--drab);
}

#ending h1 {
  font-family: var(--font-a);
  font-size: clamp(1.4rem, 4vw, 2.1rem);
  font-weight: 400;
  letter-spacing: 0.3em;
  margin: 0.75rem 0 1.75rem;
  color: var(--ink);
}

#ending button, #reset {
  font-family: var(--font-a);
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--drab);
  background: transparent;
  border: 1px solid var(--drab-lt);
  padding: 0.5rem 1rem;
  cursor: pointer;
}
#ending button:hover, #reset:hover {
  color: var(--ink);
  border-color: var(--ink);
}

/* Two-step confirm affordance — see engine.js resetArm(). A stray click costs
   a full playthrough, so the destructive state must look different. */
#reset {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  background: var(--paper-hi);
  border-color: var(--grey-mid);
  color: var(--slate);
  opacity: 0.75;
  transition: opacity 120ms linear, color 120ms linear, border-color 120ms linear;
}
#reset:hover, #reset:focus-visible {
  opacity: 1;
  color: var(--ink);
  border-color: var(--ink);
  outline: none;
}
#reset[data-armed="true"] {
  opacity: 1;
  color: var(--accent-a);
  border-color: var(--accent-a);
  box-shadow: inset 2px 0 0 var(--accent-a);
}

@media (prefers-reduced-motion: reduce) {
  #box[data-done="true"] #advance { animation: none; }
}
