/* Original Yamamori presentation, preserved from the existing game. */
:root {
    --paper:  #f3e7c9;
    --paper2: #e8d9b0;
    --ink:    #2a1f14;
    --ink2:   #4a3a28;
    --red:    #b33a3a;
    --redDk:  #7a1f1f;
    --green:  #3c6e2a;
    --greenLt:#6ba04c;
    --gold:   #c9a14a;
    --indigo: #2a4a6a;
  }
  * { box-sizing: border-box; margin: 0; padding: 0; }
  html, body {
    height: 100%;
    background: #0f0b08;
    color: var(--paper);
    font-family: "Courier New", monospace;
    overflow: hidden;
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
    overscroll-behavior: none;
    touch-action: manipulation;
  }
  body {
    display: flex;
    flex-direction: column;
    /* Game-wrap sits flush to the top of the viewport — no padding
       above it. Any extra vertical space on tall windows falls below
       the game. Solid dark background (no radial gradient) so there's
       no visible green/colour bleed anywhere around the game. */
    justify-content: flex-start;
    align-items: center;
    min-height: 100vh;
    min-height: 100dvh;
    background: #0f0b08;
  }
  #game-wrap {
    position: relative;
    /* Scale the desktop game-wrap to fill the viewport while keeping
       the 3:2 aspect of the canvas buffer, so on big monitors the
       game is much larger without changing the zoom level or
       distorting pixel art. min() clamps to whichever axis limits
       first so the wrap never overflows the viewport. */
    width:  min(100vw, calc(100dvh * 1.5));
    height: min(100dvh, calc(100vw / 1.5));
    /* Removed the 10px inset-ink border — it was pushing the bottom HUD
       bar visually up away from the map edge. Gold outline stays. */
    box-shadow:
      0 0 80px rgba(0,0,0,0.9),
      inset 0 0 0 3px var(--gold);
    background: #000;
    image-rendering: pixelated;
  }
  @media (max-width: 1000px), (max-height: 680px) {
    body { padding: 0; overflow: hidden; }
    #game-wrap {
      width: 100vw;
      height: 100vh;
      height: 100dvh;
      aspect-ratio: auto;
      box-shadow: inset 0 0 0 2px var(--gold);
    }
  }
  canvas {
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: #0f0b08;
    touch-action: none;
  }
  /* Base game-canvas rule (desktop + mobile share this): the canvas is
     positioned BETWEEN the top and bottom HUD bars so the map edges line
     up exactly with the bars — bars are "tacked on" flush to the map.
     Explicit width / height here instead of auto because a canvas has
     intrinsic dimensions (960×640 buffer) and `auto` would fall back to
     those, overflowing the box and leaving a dead zone below. */
  canvas#game {
    position: absolute;
    /* The canvas sits BELOW the top HUD bar (40px) AND the timeline
       strip (34px) — no overlap, the timeline gets its own band. */
    top: 74px;
    left: 0;
    right: 0;
    width: 100%;
    height: calc(100% - 112px);   /* 40 top bar + 34 timeline + 38 bottom bar */
    object-fit: fill;
    background: #0f0b08;
  }
  /* Full-mobile layout: canvas fills viewport, controls overlay on top */
  @media (pointer: coarse), (max-width: 800px) {
    body { background: #0f0b08; padding: 0; }
    #game-wrap {
      width: 100vw;
      height: 100vh;
      height: 100dvh;
      box-shadow: none;
      background: #0f0b08;
    }
    /* Mobile canvas fills the ENTIRE viewport — HUD bars, minimap and
       touch buttons overlay on top (they have z-index:5 + semi-opaque
       backgrounds), so the map shows through behind them instead of
       leaving black letterbox strips. object-fit:cover preserves the
       3:2 buffer aspect by cropping a little; the camera soft-clamp
       keeps the player centred so the crop is never near the player. */
    canvas#game {
      /* Mobile: canvas sits below the top HUD bar + timeline strip
         and above the bottom bar — no overlap, same as desktop. */
      top: calc(78px + env(safe-area-inset-top, 0px));
      left: 0;
      right: 0;
      transform: none;
      width: 100%;
      height: calc(100% - 78px - 38px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
      aspect-ratio: auto;
      max-width: 100vw;
      object-fit: fill;
    }
    /* Mobile menus: prioritise readability over density. Fonts a touch bigger
       than desktop, with roomier line-height and tap targets. */
    .overlay { padding: 12px; }
    .paper-panel {
      padding: 24px 20px;
      max-width: 96vw;
      max-height: 94vh;
      box-shadow: 4px 4px 0 rgba(0,0,0,0.55);
    }
    .paper-panel::before, .paper-panel::after { width: 86%; }
    h1 { font-size: 34px; letter-spacing: 3px; }
    h2 { font-size: 18px; }
    .kanji-big { font-size: 32px; margin-bottom: 14px; letter-spacing: 10px; }
    .kanji { font-size: 20px; letter-spacing: 5px; }
    .subtitle { font-size: 15px; line-height: 1.7; margin-bottom: 14px; }
    .era-stamp { font-size: 13px; padding: 5px 16px; }
    /* Standardise DEFEND / POWER-UPS text to 12px across all three
       title-screen boxes (DEFEND / MOVE-ACT / POWER-UPS / HOW IT LOOKS
       table). Consistent body text on mobile. */
    .controls-box { font-size: 12px; line-height: 1.75; padding: 12px 14px; }
    .controls-box .ctl-row { font-size: 12px; line-height: 42px; margin: 4px 0; }
    .controls-box .ctl-sub { font-size: 12px; line-height: 44px; margin: 2px 0 10px 0; }
    .infographic-title { font-size: 13px; letter-spacing: 2px; }
    .infographic-caption { font-size: 14px; line-height: 1.55; }
    .glossary { column-count: 1; font-size: 13px; line-height: 1.8; padding: 14px 16px; }
    .fact-strip { font-size: 13px; line-height: 1.65; }
    .moral { font-size: 14px; line-height: 1.8; padding: 18px; }
    .citation-details summary { font-size: 13px; padding: 6px 0; }
    .citation { font-size: 12px; line-height: 1.7; }
    .stats-grid   { grid-template-columns: repeat(2, 1fr); gap: 12px; }
    /* Extra-specific so it wins over the later desktop .stats-grid-5. */
    .paper-panel .stats-grid-5 { grid-template-columns: repeat(3, 1fr); }
    .stat-cell { padding: 14px 10px; }
    .stat-cell .num { font-size: 30px; }
    .stat-cell .lbl { font-size: 12px; }
    button.edo-btn { padding: 16px 34px; font-size: 16px; min-height: 52px; letter-spacing: 3px; }
    .btn-row { gap: 14px; margin-top: 10px; }
    /* HUD on mobile — fonts a hair bigger than the old tiny 11-12px.
       Background is semi-transparent on touch so the map shows through
       behind the bars; a backdrop blur + text shadow keep readability. */
    .hud-bar {
      font-size: 13px; padding: 0 12px; gap: 10px;
      background: rgba(15, 11, 8, 0.48);
      backdrop-filter: blur(6px);
      -webkit-backdrop-filter: blur(6px);
      text-shadow: 0 1px 2px rgba(0,0,0,0.9), 0 0 4px rgba(0,0,0,0.6);
    }
    .hud-top { height: calc(44px + env(safe-area-inset-top, 0px)); padding-top: env(safe-area-inset-top, 0px); }
    .hud-top .hud-slot-center { font-size: 15px; }
    .hud-bottom { height: calc(38px + env(safe-area-inset-bottom, 0px)); padding-bottom: env(safe-area-inset-bottom, 0px); }
    .hud-bottom .hud-slot { font-size: 12px; }
    .minimap { background: rgba(15, 11, 8, 0.50); }
    .season-banner { font-size: 18px; padding: 14px 14px; letter-spacing: 2px; }
    .toast { font-size: 13px; padding: 6px 14px; }
    /* Keep the action hint centered over YAMAMORI on mobile too; override
       only the font. (Base CSS sets the top-center position.) */
    .action-hint { font-size: 11px; padding: 4px 10px; }
    /* ACT = big round bottom-right (opposite the joystick). PAUSE = tiny
       top-left pill so TIME stays in the corner. */
    .mc-action { width: 128px; height: 128px; font-size: 22px; bottom: calc(44px + env(safe-area-inset-bottom, 0px)); right: calc(24px + env(safe-area-inset-right, 0px)); top: auto; left: auto; }
    .mc-esc { width: 60px; height: 28px; font-size: 11px; top: calc(4px + env(safe-area-inset-top, 0px)); left: calc(8px + env(safe-area-inset-left, 0px)); right: auto; bottom: auto; }
  }
  /* Portrait orientation tip for touch phones */
  body.touch.portrait #portrait-hint { display: flex; }
  /* Mobile control instructions on title screen */
  body.touch .controls-box.keyboard { display: none; }
  body.touch .controls-box.mobile { display: block; }
  body:not(.touch) .controls-box.mobile { display: none; }
  canvas {
    display: block;
    width: 100%;
    height: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
  }
  .overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;  /* stick content to the top */
    /* Fully opaque — we don't want the canvas map bleeding through the
       title / pause / end screens. */
    background: #0f0b08;
    padding: 8px 12px;             /* tight padding so content hugs top */
    text-align: center;
    z-index: 10;
    overflow: auto;
  }
  .overlay.hidden { display: none; }
  /* Pause overlay extends a hair past the game-wrap edges so any thin
     leak from the gold border / canvas on the LEFT is fully covered. */
  #pause-screen.overlay { left: -8px; right: -8px; }
  .paper-panel {
    background: var(--paper);
    color: var(--ink);
    padding: 32px 44px;
    max-width: 780px;
    max-height: 92vh;
    overflow-y: auto;
    border: 3px double var(--ink);
    box-shadow: 10px 10px 0 rgba(0,0,0,0.55);
    position: relative;
    background-image:
      repeating-linear-gradient(45deg, transparent, transparent 14px, rgba(42,31,20,0.025) 14px, rgba(42,31,20,0.025) 15px),
      radial-gradient(ellipse at top, rgba(42,31,20,0.04), transparent 70%);
  }
  /* Red dividers flow with panel content so they never overlap scrolled
     glossary/history content — they move up and down with the scroll. */
  .paper-panel::before, .paper-panel::after {
    content: "";
    display: block;
    width: 82%;
    height: 2px;
    background: var(--red);
    margin: 0 auto;
    pointer-events: none;
  }
  .paper-panel::before { margin-bottom: 18px; }
  .paper-panel::after  { margin-top: 18px; }
  .paper-panel::-webkit-scrollbar { width: 10px; }
  .paper-panel::-webkit-scrollbar-track { background: rgba(0,0,0,0.05); }
  .paper-panel::-webkit-scrollbar-thumb { background: var(--ink); }

  h1 {
    font-size: 44px;
    margin-bottom: 4px;
    letter-spacing: 3px;
    color: var(--red);
    text-shadow: 3px 3px 0 rgba(0,0,0,0.08);
  }
  h2 {
    font-size: 20px;
    color: var(--red);
    margin: 20px 0 10px;
    letter-spacing: 1px;
    border-bottom: 1px solid var(--ink);
    padding-bottom: 4px;
    display: inline-block;
  }
  .kanji-big {
    font-size: 34px;
    color: var(--ink);
    margin: 6px 0 18px;
    letter-spacing: 8px;
    font-weight: bold;
  }
  .kanji {
    font-size: 22px;
    color: var(--ink);
    margin-bottom: 14px;
    font-weight: bold;
    letter-spacing: 4px;
  }
  .subtitle {
    font-size: 14px;
    line-height: 1.7;
    margin-bottom: 16px;
    color: var(--ink);
    text-align: left;
  }
  .subtitle.center { text-align: center; }
  .era-stamp {
    display: inline-block;
    border: 2px solid var(--red);
    color: var(--red);
    padding: 4px 14px;
    font-size: 12px;
    letter-spacing: 3px;
    margin: 6px 0 14px;
    transform: rotate(-2deg);
    font-weight: bold;
  }
  /* End-screen verdict pill — sits above the title and reads at a
     glance: green pill = win, red pill = loss. */
  .verdict-badge {
    display: inline-block;
    padding: 6px 22px;
    font-size: 18px;
    font-weight: 800;
    letter-spacing: 6px;
    margin: 0 0 10px;
    border: 3px solid;
    box-shadow: 3px 3px 0 var(--ink);
  }
  .verdict-badge.win  { background: var(--green);  color: var(--paper); border-color: var(--ink); }
  .verdict-badge.loss { background: var(--redDk);  color: var(--paper); border-color: var(--ink); }
  .end-title.win  { color: var(--green); }
  .end-title.loss { color: var(--redDk); }
  .controls-box {
    background: rgba(42, 31, 20, 0.08);
    padding: 14px 18px;
    margin: 14px 0;
    font-size: 13px;
    line-height: 1.9;
    text-align: left;
    border-left: 4px solid var(--red);
  }
  .controls-box b { color: var(--red); }
  .controls-box .j { color: var(--ink2); font-size: 12px; margin-left: 6px; }
  .controls-box .ctl-row {
    display: block;
    margin: 4px 0;
    line-height: 40px;
  }
  .controls-box .ctl-row b { display: inline-block; min-width: 74px; }
  /* Key-binding rows (ESC pause · M mute) shouldn't inherit the 74px
     label width — that was for the numbered step labels only. */
  .controls-box .ctl-row.ctl-keys b { min-width: 0; margin-right: 4px; display: inline; }
  .controls-box .ctl-sub {
    margin: 2px 0 8px 40px;
    font-size: 12px;
    line-height: 42px;
    color: var(--ink2);
    /* Force the three icon+phrase units onto one horizontal line on
       web; they may overflow slightly on narrow windows rather than
       wrapping to a ragged second row. */
    white-space: nowrap;
  }
  /* Smaller inline icons inside the DEFEND / ACT sub-rows so three
     units fit comfortably on one line. */
  .controls-box .ctl-sub canvas.inst-icon {
    width: 26px;
    height: 26px;
    margin: 0 2px;
  }
  canvas.inst-icon {
    display: inline-block;
    width: 36px;
    height: 36px;
    vertical-align: middle;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    margin: 0 3px;
    /* Grass-green background matches the in-game world under each
       sprite and gives good contrast with the dark poacher, brown
       bucket, blue river, etc. Overrides the dark base `canvas` rule. */
    background: #5c8a3a;
    border-radius: 2px;
  }

  /* Infographic walkthrough panels */
  .infographic {
    margin: 14px 0 10px;
    padding: 12px 14px;
    background: rgba(42,31,20,0.06);
    border: 1px dashed var(--ink);
  }
  .infographic-title {
    font-size: 12px;
    color: var(--red);
    letter-spacing: 2px;
    font-weight: bold;
    margin-bottom: 10px;
    text-align: center;
  }
  .infographic-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
  }
  .infographic-step {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
  }
  canvas.infographic-panel {
    display: block;
    width: 440px;
    height: 124px;
    max-width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background: #5c8a3a;
    border: 2px solid var(--ink);
    margin-bottom: 6px;
  }
  .infographic-caption {
    font-size: 13px;
    color: var(--ink);
    line-height: 1.5;
    max-width: 440px;
  }
  /* Tabular infographic for mobile: columns = [#, icon, thing, how]. Hidden
     on desktop (big canvas walkthrough is shown instead). Size matches the
     other title-screen boxes (DEFEND / MOVE-ACT / POWER-UPS). */
  .infographic-table {
    display: none;
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
    color: var(--ink);
  }
  .infographic-table td {
    padding: 8px 6px;
    border-bottom: 1px dashed rgba(42,31,20,0.28);
    vertical-align: middle;
    line-height: 1.45;
  }
  .infographic-table tr:last-child td { border-bottom: none; }
  .infographic-table .igt-num  { width: 26px; text-align: center; font-weight: bold; color: var(--red); font-size: 14px; }
  .infographic-table .igt-icon { width: 44px; text-align: center; }
  .infographic-table .igt-icon canvas.inst-icon { margin: 0; vertical-align: middle; }
  .infographic-table .igt-what { width: 92px; white-space: nowrap; }
  .infographic-table .igt-how  { color: var(--ink); }
  .infographic-table .igt-ex   { color: var(--ink2); font-style: italic; }

  @media (max-width: 860px), (pointer: coarse) {
    /* On mobile: hide the big canvas grid, show the compact table.
       Red-dashed box so the walkthrough still stands out while scrolling. */
    .infographic {
      border: 2px dashed var(--red);
      background: rgba(178, 58, 58, 0.05);
      padding: 14px 10px;
    }
    .infographic-title   { font-size: 14px; margin-bottom: 10px; }
    .infographic-desktop { display: none; }
    .infographic-table   { display: table; }
  }
  .infographic-caption b { color: var(--red); }

  /* Side-by-side pair of intro artifacts (1689 Edo map + 1856
     Nihonbashi yukibare) so the player sees "before/after" of the
     capital they are keeping the forest for. */
  .intro-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin: 14px 0 4px;
  }
  .intro-pair .artifact-frame {
    margin: 0;
    max-width: 100%;
  }
  .intro-pair .artifact-img {
    height: 200px;
    object-fit: cover;
  }
  @media (max-width: 860px), (pointer: coarse) {
    .intro-pair { grid-template-columns: 1fr; gap: 8px; }
    .intro-pair .artifact-img { height: 160px; }
  }

  /* Historical artifact frame — the actual Edo painted scroll. */
  .artifact-frame {
    position: relative;
    margin: 6px auto 0;
    max-width: 560px;
    border: 3px double var(--ink);
    background: #1a0f08;
    padding: 6px;
    box-shadow: 6px 6px 0 rgba(0,0,0,0.45);
  }
  .artifact-img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 1px;
  }
  .artifact-cap {
    color: #c8b88c;
    font-size: 11px;
    text-align: center;
    padding: 6px 8px 2px;
    letter-spacing: 0.4px;
    line-height: 1.5;
  }
  .artifact-cap b { color: #f0d890; }

  /* Step navigator (Story › Rules › Patrol) shown at the top of intro/rules. */
  .step-row {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 8px;
    margin-bottom: 14px;
    font-size: 11px;
    letter-spacing: 2px;
    color: var(--ink3, #8a7a5a);
    flex-wrap: wrap;
  }
  .step {
    padding: 4px 10px;
    border: 1px solid rgba(42,31,20,0.25);
    background: rgba(42,31,20,0.04);
    color: var(--ink2);
    font-weight: bold;
  }
  .step.active {
    background: var(--red);
    color: var(--paper);
    border-color: var(--ink);
    box-shadow: 2px 2px 0 var(--ink);
  }
  .step.done {
    background: rgba(60,110,42,0.12);
    border-color: var(--green);
    color: var(--green);
  }
  .step-sep { color: var(--ink3, #b8a672); font-size: 14px; }

  /* Between-cycle transition modal. Uses the SAME paper-panel base
     as the intro and end screens — same washi background, same red
     dividing rules, no tilt — so all three storytelling screens
     read as pages of one book. Only layout extras (centring,
     width) live here; the hanko seal is the one period flourish. */
  .quote-panel {
    max-width: 560px;
    text-align: center;
  }
  /* Hanko (red square seal) at upper-right of the artifact — classic
     Edo-period mark of authenticity. */
  .quote-panel .hanko {
    position: absolute;
    top: 22px;
    right: 26px;
    width: 46px;
    height: 46px;
    background: #b3261c;
    color: #fff4d4;
    font-weight: 900;
    font-size: 18px;
    letter-spacing: 1px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    line-height: 1;
    box-shadow:
      0 0 0 1px #5a1208 inset,
      0 0 0 4px #b3261c inset,
      0 0 0 5px #5a1208 inset,
      2px 3px 0 rgba(0,0,0,0.18);
    transform: rotate(7deg);
    text-shadow: 0 1px 0 rgba(0,0,0,0.18);
  }
  .quote-panel .hanko span { display: block; font-size: 14px; }
  .quote-mark {
    font-size: 56px;
    line-height: 0.8;
    color: #8a2a1a;
    font-weight: bold;
    margin: 2px 0 -10px;
    text-align: left;
    padding-left: 18px;
    font-family: serif;
  }
  .quote-mark.right {
    text-align: right;
    padding-left: 0;
    padding-right: 18px;
    margin-top: -14px;
    margin-bottom: 4px;
  }
  .quote-body {
    font-size: 19px;
    line-height: 1.7;
    font-style: italic;
    color: #3a2410;
    padding: 4px 28px;
    margin: 0;
    text-align: left;
    letter-spacing: 0.3px;
    font-family: 'Newsreader', Georgia, serif;
  }
  .quote-body b { color: #8a2a1a; font-style: normal; }
  .quote-attrib {
    font-size: 11px;
    color: #6a4a2a;
    letter-spacing: 3px;
    margin: 10px 0 4px;
    text-transform: uppercase;
    font-weight: bold;
  }
  .quote-source {
    font-size: 11px;
    color: #6a4a2a;
    font-style: italic;
    margin: 0 0 4px;
    letter-spacing: 0.6px;
  }
  /* era-stamp and kanji-big inherit the shared paper-panel styling
     — no quote-screen-specific overrides, so the header reads
     identically across intro, transition and end screens. */
  .quote-reward {
    margin: 14px auto 2px;
    padding: 9px 14px;
    background: rgba(60,110,42,0.10);
    border: 1px dashed var(--green);
    max-width: 440px;
    font-size: 12px;
    line-height: 1.55;
    color: #3a2410;
  }

  /* Cinematic storyboard reveal — when the quote panel opens, its
     pieces fade-slide in one after another, like flipping through an
     unrolled scroll. The staggered delays add up to ~1.6s for the
     full reveal so the player feels time passing between cycles. */
  @keyframes scrollSlideIn {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  @keyframes hankoSlam {
    0%   { opacity: 0; transform: rotate(7deg) scale(1.8); }
    60%  { opacity: 1; transform: rotate(7deg) scale(0.92); }
    100% { opacity: 1; transform: rotate(7deg) scale(1);   }
  }
  @keyframes threatStamp {
    0%   { opacity: 0; transform: rotate(-1deg) scale(1.6); }
    55%  { opacity: 1; transform: rotate(-1deg) scale(0.92); }
    100% { opacity: 1; transform: rotate(-1deg) scale(1);   }
  }
  /* Only animate when the panel is actually shown — gate by parent
     :not(.hidden) on #quote-screen so reloads / hiding don't replay. */
  #quote-screen:not(.hidden) .quote-panel > .era-stamp,
  #quote-screen:not(.hidden) .quote-panel > .kanji-big,
  #quote-screen:not(.hidden) .quote-panel > .quote-reveal,
  #quote-screen:not(.hidden) .quote-panel > .quote-task,
  #quote-screen:not(.hidden) .quote-panel > .artifact-frame,
  #quote-screen:not(.hidden) .quote-panel > .quote-mark,
  #quote-screen:not(.hidden) .quote-panel > .quote-body,
  #quote-screen:not(.hidden) .quote-panel > .quote-attrib,
  #quote-screen:not(.hidden) .quote-panel > .quote-source,
  #quote-screen:not(.hidden) .quote-panel > .quote-reward,
  #quote-screen:not(.hidden) .quote-panel > .btn-row {
    animation: scrollSlideIn 0.55s ease-out backwards;
  }
  #quote-screen:not(.hidden) .quote-panel > .hanko {
    animation: hankoSlam 0.5s cubic-bezier(0.18, 0.89, 0.32, 1.28) backwards;
    animation-delay: 0.05s;
  }
  #quote-screen:not(.hidden) .quote-panel > .quote-threat {
    animation: threatStamp 0.55s cubic-bezier(0.18, 0.89, 0.32, 1.28) backwards;
  }
  #quote-screen:not(.hidden) .quote-panel > .era-stamp                  { animation-delay: 0.15s; }
  #quote-screen:not(.hidden) .quote-panel > .kanji-big                  { animation-delay: 0.35s; }
  #quote-screen:not(.hidden) .quote-panel > .quote-threat               { animation-delay: 0.55s; }
  #quote-screen:not(.hidden) .quote-panel > .quote-reveal               { animation-delay: 0.80s; }
  #quote-screen:not(.hidden) .quote-panel > .quote-task                 { animation-delay: 1.00s; }
  #quote-screen:not(.hidden) .quote-panel > .artifact-frame:nth-of-type(1) { animation-delay: 1.25s; }
  #quote-screen:not(.hidden) .quote-panel > .artifact-frame:nth-of-type(2) { animation-delay: 1.50s; }
  #quote-screen:not(.hidden) .quote-panel > .artifact-frame:nth-of-type(3) { animation-delay: 1.75s; }
  #quote-screen:not(.hidden) .quote-panel > .quote-mark:nth-of-type(1)  { animation-delay: 1.95s; }
  #quote-screen:not(.hidden) .quote-panel > .quote-body                 { animation-delay: 2.00s; }
  #quote-screen:not(.hidden) .quote-panel > .quote-mark:nth-of-type(2)  { animation-delay: 2.10s; }
  #quote-screen:not(.hidden) .quote-panel > .quote-attrib               { animation-delay: 2.30s; }
  #quote-screen:not(.hidden) .quote-panel > .quote-source               { animation-delay: 2.40s; }
  #quote-screen:not(.hidden) .quote-panel > .quote-reward               { animation-delay: 2.55s; }
  #quote-screen:not(.hidden) .quote-panel > .btn-row                    { animation-delay: 2.75s; }
  /* Threat reveal pill — the headline of every cycle transition.
     Reads as a stamped notice ("THE NEXT THING") above the print. */
  .quote-threat {
    display: inline-block;
    background: #8a2a1a;
    color: #fff4d4;
    padding: 5px 18px;
    font-size: 14px;
    font-weight: 800;
    letter-spacing: 4px;
    margin: 4px 0 8px;
    box-shadow: 3px 3px 0 #3a2410;
    transform: rotate(-1deg);
  }
  .quote-reveal {
    font-size: 13px;
    line-height: 1.65;
    color: #3a2410;
    max-width: 480px;
    margin: 4px auto 14px;
    text-align: center;
    font-style: italic;
  }
  .quote-reveal b { color: #8a2a1a; font-style: normal; }
  /* YOUR TASK block — the explicit goal for the cycle the player is
     about to enter. Styled quietly to SIT WITHIN the paper UI: a
     soft tinted panel with a thin dashed green rule (matching the
     quote-reward block below it), an understated label, no hard
     shadow. Clear, but part of the page — not a billboard. */
  .quote-task {
    max-width: 500px;
    margin: 6px auto 16px;
    padding: 10px 18px 11px;
    background: rgba(60,110,42,0.07);
    border: 1px dashed var(--green);
    text-align: center;
  }
  .quote-task .qt-label {
    display: block;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 3px;
    color: var(--green);
    margin-bottom: 4px;
  }
  .quote-task .qt-text {
    display: block;
    font-size: 14px;
    line-height: 1.65;
    color: var(--ink);
    font-weight: bold;
  }
  /* The Hokusai/Hiroshige print inside the artifact frame on the quote
     panel — sized down a touch from the intro scroll so the body and
     citation still fit on one screen. */
  .quote-print {
    margin: 4px auto 12px;
    max-width: 460px;
    background: #2a1810;
    box-shadow: 4px 4px 0 rgba(0,0,0,0.5);
  }
  .quote-print .artifact-img { max-height: 240px; object-fit: cover; }
  @media (max-width: 860px), (pointer: coarse) {
    .quote-threat { font-size: 12px; letter-spacing: 3px; padding: 5px 14px; }
    .quote-reveal { font-size: 12px; }
    .quote-task .qt-text { font-size: 13px; }
    .quote-print .artifact-img { max-height: 180px; }
  }

  button.edo-btn {
    background: var(--red);
    color: var(--paper);
    border: none;
    padding: 14px 36px;
    font-size: 16px;
    font-family: inherit;
    font-weight: bold;
    cursor: pointer;
    letter-spacing: 3px;
    margin-top: 14px;
    box-shadow: 4px 4px 0 var(--ink);
    transition: transform 0.1s, box-shadow 0.1s;
  }
  button.edo-btn:hover  { transform: translate(-2px, -2px); box-shadow: 6px 6px 0 var(--ink); }
  button.edo-btn:active { transform: translate(2px, 2px);   box-shadow: 2px 2px 0 var(--ink); }
  button.edo-btn.ghost {
    background: var(--paper);
    color: var(--ink);
    border: 2px solid var(--ink);
    box-shadow: 4px 4px 0 var(--ink);
  }

  /* End-screen rating: the star verdict + the persistent best. */
  .end-rating {
    margin: 8px auto 4px;
    text-align: center;
  }
  .end-stars {
    font-size: 30px;
    letter-spacing: 8px;
    line-height: 1;
    margin-bottom: 6px;
  }
  .end-stars .st-on  { color: var(--gold); text-shadow: 0 2px 4px rgba(0,0,0,0.35); }
  .end-stars .st-off { color: rgba(42,31,20,0.22); }
  .end-best {
    font-size: 12px;
    letter-spacing: 2px;
    color: var(--ink2);
    font-weight: bold;
  }
  .end-best .nb {
    display: inline-block;
    background: var(--gold);
    color: var(--ink);
    padding: 2px 9px;
    margin-left: 8px;
    font-weight: 800;
    letter-spacing: 1.5px;
    box-shadow: 2px 2px 0 var(--ink);
    transform: rotate(-3deg);
  }

  /* Finale print on the end screen — the Surugachō Hiroshige, scaled
     so the rebuilt-Edo street and Mt Fuji are clearly readable. */
  .end-finale {
    margin: 8px auto 16px;
    max-width: 600px;
    background: #2a1810;
    box-shadow: 6px 6px 0 rgba(0,0,0,0.5);
  }
  .end-finale .artifact-img { max-height: 280px; object-fit: cover; }
  @media (max-width: 860px), (pointer: coarse) {
    .end-finale .artifact-img { max-height: 190px; }
  }
  /* Artifact gallery on the end screen — chronological strip of every
     historical print/manuscript the player encountered, four panels
     wide. Each panel: year tab, image, threat label, attribution. */
  .artifact-gallery-title {
    font-size: 12px;
    color: var(--red);
    letter-spacing: 3px;
    font-weight: 800;
    text-align: center;
    margin: 14px 0 8px;
  }
  .cycle-preview {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
    margin: 6px 0 14px;
  }
  /* End-screen artifact gallery — now 6 cards across so the
     pre-cycle Edo map (1689) and the post-cycle Hiroshige
     Nihonbashi yukibare (1856) bracket the four chapter prints. */
  .artifact-gallery {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 8px;
    margin: 6px 0 14px;
  }
  .cycle-preview-title {
    font-size: 11px;
    color: var(--red);
    letter-spacing: 3px;
    font-weight: 800;
    text-align: center;
    margin: 18px 0 8px;
  }
  .art-card {
    background: #1a0f08;
    border: 2px solid var(--ink);
    box-shadow: 3px 3px 0 rgba(0,0,0,0.4);
    overflow: hidden;
    position: relative;
    display: flex;
    flex-direction: column;
  }
  /* The chapter-tag identifies WHICH of the four chapters this
     artifact belongs to. Context cards (1689 atlas, 1856 Hiroshige)
     get a subdued tag so the four chapter prints visually outrank
     them and the 4-cycle structure stays unambiguous. */
  .art-chapter-tag {
    background: var(--gold);
    color: #2a1f14;
    text-align: center;
    font-weight: 800;
    font-size: 9px;
    letter-spacing: 2px;
    padding: 3px 0 2px;
    border-bottom: 1px solid var(--ink);
  }
  .art-card.art-context .art-chapter-tag {
    background: rgba(201,161,74,0.25);
    color: #9b8a6a;
    font-weight: 700;
    letter-spacing: 3px;
  }
  .art-card.art-context {
    opacity: 0.85;
    border-style: dashed;
  }
  .art-year {
    background: var(--red);
    color: var(--paper);
    text-align: center;
    font-weight: 800;
    font-size: 12px;
    letter-spacing: 2px;
    padding: 4px 0;
  }
  .art-card.art-context .art-year {
    background: #6a4a2a;
  }
  .art-img {
    display: block;
    width: 100%;
    height: 96px;
    object-fit: cover;
    background: #2a1810;
  }
  .art-meta {
    padding: 6px 8px 8px;
    font-size: 10px;
    line-height: 1.4;
    color: #c8b88c;
    flex: 1;
  }
  .art-meta b   { color: #ffd860; display: block; letter-spacing: 1.5px; font-size: 10px; }
  .art-meta i   { color: #e8d9b0; font-style: italic; }
  .art-meta .src { display: block; margin-top: 3px; color: #9b8a6a; font-size: 9px; }
  @media (max-width: 860px), (pointer: coarse) {
    .artifact-gallery { grid-template-columns: repeat(3, 1fr); gap: 6px; }
    .cycle-preview    { grid-template-columns: repeat(2, 1fr); }
    .art-img          { height: 96px; }
    .artifact-gallery .art-img { height: 84px; }
  }

  /* Cycle-by-cycle outcome strip — 4 small cards across, one per cycle. */
  .cycle-strip {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
    margin: 14px 0;
  }
  .cycle-strip .cyc {
    background: rgba(42, 31, 20, 0.06);
    border: 1px solid var(--ink);
    padding: 10px 8px;
    text-align: center;
    position: relative;
    box-shadow: 2px 2px 0 rgba(0,0,0,0.18);
  }
  .cycle-strip .cyc .yr { font-size: 13px; font-weight: bold; color: var(--ink); letter-spacing: 1px; }
  .cycle-strip .cyc .era { font-size: 14px; color: var(--red); font-weight: 800; letter-spacing: 1px; margin: 2px 0 4px; }
  .cycle-strip .cyc .threat { font-size: 11px; color: var(--ink2); letter-spacing: 2px; margin-bottom: 6px; text-transform: uppercase; }
  .cycle-strip .cyc .row { font-size: 11px; color: var(--ink); line-height: 1.55; display: flex; justify-content: space-between; padding: 0 2px; }
  .cycle-strip .cyc .row b { color: var(--green); font-weight: 800; }
  .cycle-strip .cyc .row .bad { color: var(--redDk); font-weight: 800; }
  .cycle-strip .cyc.tier-good { border-color: var(--green); }
  .cycle-strip .cyc.tier-mid  { border-color: #c9a14a; }
  .cycle-strip .cyc.tier-loss { border-color: var(--redDk); background: rgba(122,31,31,0.07); }
  @media (max-width: 860px), (pointer: coarse) {
    .cycle-strip { grid-template-columns: repeat(2, 1fr); gap: 8px; }
    .cycle-strip .cyc { padding: 8px 6px; }
  }

  .stats-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
    margin: 16px 0;
  }
  /* Legacy 5-cell layout still here for backward compat, but the live
     end screen uses .stats-grid-4 + a separate .hero-lost block above
     it so TREES LOST reads as the headline. */
  .stats-grid-5 { grid-template-columns: repeat(5, 1fr); }
  .stats-grid-4 { grid-template-columns: repeat(4, 1fr); }

  /* Subtle commitment-signal line under each BEGIN cluster. Keeps the
     same paper-panel vocabulary (ink2 text on the paper background)
     so it reads as a system note, not marketing copy. */
  .play-meta {
    margin-top: 10px;
    text-align: center;
    font-size: 11px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--ink2);
    opacity: 0.85;
  }
  .stat-cell {
    background: rgba(42, 31, 20, 0.06);
    padding: 10px 8px;
    border: 1px solid var(--ink);
  }
  .stat-cell .num { font-size: 26px; font-weight: bold; color: var(--red); }
  .stat-cell .lbl { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; }

  /* HERO LOST stat — the emotional headline of the run. Big number
     centred under the cycle strip, coloured green at zero (no cedars
     died in 200 years — extraordinary), amber when the toll is small,
     red when serious. Subtitle anchors it to the patrol length so it
     can't be read out of context. */
  .hero-lost {
    text-align: center;
    margin: 18px 0 6px;
    padding: 14px 12px;
    border-top: 1px solid var(--ink);
    border-bottom: 1px solid var(--ink);
  }
  .hero-lost-num {
    font-family: -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
    font-size: 72px;
    font-weight: 800;
    letter-spacing: -2px;
    line-height: 1;
    color: #2d6a32; /* green at zero */
  }
  .hero-lost.warn .hero-lost-num { color: #c08a30; }
  .hero-lost.bad  .hero-lost-num { color: #b33a3a; }
  .hero-lost-lbl {
    margin-top: 4px;
    font-weight: 700;
    letter-spacing: 4px;
    font-size: 13px;
    color: var(--ink);
  }
  .hero-lost-sub {
    margin-top: 4px;
    font-size: 12px;
    color: var(--ink2);
    font-style: italic;
  }

  .inventory {
    background: #fffaec;
    padding: 14px 18px;
    margin: 10px 0;
    font-size: 13px;
    line-height: 1.7;
    text-align: left;
    border: 1px solid var(--ink);
    font-family: "Courier New", monospace;
  }
  .inventory .hdr {
    font-size: 12px;
    color: var(--red);
    letter-spacing: 2px;
    margin-bottom: 6px;
    border-bottom: 1px dashed var(--ink);
    padding-bottom: 4px;
  }
  .inv-row { display: flex; justify-content: space-between; font-size: 12px; }
  .inv-row .k { color: var(--ink2); }
  .inv-row .v { color: var(--ink); font-weight: bold; }

  .moral {
    background: #fff9e8;
    padding: 16px;
    margin-top: 16px;
    font-size: 13px;
    line-height: 1.75;
    border: 2px solid var(--green);
    text-align: left;
  }
  .moral b { color: var(--green); }
  .moral em { color: var(--redDk); font-style: normal; font-weight: bold; }

  .citation {
    font-size: 11px;
    margin-top: 6px;
    color: #554;
    font-style: italic;
    text-align: left;
    line-height: 1.6;
    padding: 10px 4px 4px;
  }
  .citation-details {
    margin-top: 14px;
    border-top: 1px dashed var(--ink);
    padding-top: 8px;
  }
  .citation-details summary {
    cursor: pointer;
    font-size: 12px;
    letter-spacing: 2px;
    color: var(--red);
    font-weight: bold;
    outline: none;
    list-style: none;
    padding: 4px 0;
  }
  .citation-details summary::-webkit-details-marker { display: none; }
  .citation-details summary::before { content: "▸ "; }
  .citation-details[open] summary::before { content: "▾ "; }
  .citation b { color: var(--ink); font-style: normal; }
  .citation a { color: var(--red); text-decoration: none; }
  .citation a:hover { text-decoration: underline; }

  .hud-note {
    position: absolute;
    bottom: -24px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 10px;
    color: #9b8a6a;
    letter-spacing: 2px;
  }

  /* Crisp HTML HUD overlays (replace blurry canvas text) */
  .hud-bar {
    position: absolute;
    left: 0;
    right: 0;
    z-index: 5;
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: rgba(15, 11, 8, 0.94);
    color: var(--paper);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    font-weight: 700;
    font-size: 14px;
    letter-spacing: 0.5px;
    padding: 0 16px;
    pointer-events: none;
  }
  .hud-top {
    top: 0;
    height: 40px;
    border-bottom: 2px solid var(--gold);
    box-shadow: inset 0 -1px 0 rgba(201,161,74,0.3);
  }
  /* Three-slot top bar: wave (left) | "YAMAMORI 山守" (center) | time (right,
     big gold clock). Slots are inline-flex so we align their text via
     justify-content (text-align is a no-op on flex containers). On touch the
     ACT / PAUSE buttons have moved OUT of the bar (ACT = bottom-right big
     round, PAUSE = tiny top-left pill), so the bar gets its full width back. */
  .hud-top .hud-slot-left   { flex: 1 1 0; justify-content: flex-start; }
  .hud-top .hud-slot-center { flex: 0 0 auto; justify-content: center; color: var(--gold); letter-spacing: 2px; font-weight: 800; margin: 0 28px; }
  .hud-top .hud-slot-right  { flex: 1 1 0; justify-content: flex-end; font-size: 16px; color: var(--gold); letter-spacing: 1px; padding-left: 12px; }
  /* On touch (phone) PAUSE is removed, so the bar gets its normal padding
     back — WAVE sits flush with the left gold border. */
  body.touch .hud-top .hud-slot-center { margin: 0 14px; }
  .hud-bottom {
    bottom: 0;
    height: 38px;
    border-top: 2px solid var(--gold);
    box-shadow: inset 0 1px 0 rgba(201,161,74,0.3);
    gap: 18px;
  }
  .hud-bar.hidden { display: none; }
  .hud-bar .hud-slot {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
  }
  .hud-bar .kanji-lbl { color: #9b8a6a; font-weight: 500; }

  #hud-score    { color: var(--gold); }
  #hud-trees    { color: #9fd06c; }
  #hud-wave     { color: #9fd06c; }
  #hud-wave.w2  { color: #ffd860; }
  #hud-wave.w3  { color: #ffb060; }
  #hud-wave.w4  { color: #ff7a5a; }
  #hud-buff     { color: #9b8a6a; }
  #hud-buff.active { color: var(--gold); }
  /* TREES LOST is the emotional metric. Green at zero (the run is intact),
     amber once any cedar dies, red when the toll passes 4 — the colour does
     the work, no need to add a separate icon. Slightly larger than score so
     it visually outranks it. */
  #hud-lost          { color: #9fd06c; font-size: 15px; }
  #hud-lost.warn     { color: #ffc850; }
  #hud-lost.bad      { color: #ff7a5a; }
  #hud-lost.bad.pulse { animation: lostPulse 0.5s ease-out; }
  @keyframes lostPulse {
    0%   { transform: scale(1.0); text-shadow: 0 0 0 rgba(255,90,90,0); }
    40%  { transform: scale(1.18); text-shadow: 0 0 12px rgba(255,90,90,0.7); }
    100% { transform: scale(1.0); text-shadow: 0 0 0 rgba(255,90,90,0); }
  }

  /* ================= MOBILE TOUCH CONTROLS ================= */
  .mobile-controls {
    display: none;
    position: absolute;
    inset: 0;
    z-index: 8;
    pointer-events: none;
  }
  body.touch .mobile-controls { display: block; }
  body.touch .hud-note { display: none; }

  .mc-btn {
    position: absolute;
    pointer-events: auto;
    background: rgba(15, 11, 8, 0.78);
    border: 2px solid var(--gold);
    color: var(--paper);
    font-family: -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
    font-weight: 700;
    user-select: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: transparent;
    touch-action: none;
    box-shadow: 0 4px 0 rgba(0,0,0,0.3);
    transition: transform 0.08s, background 0.08s;
  }
  .mc-btn:active, .mc-btn.pressed {
    background: var(--red);
    transform: translateY(2px);
    box-shadow: 0 2px 0 rgba(0,0,0,0.3);
  }

  /* JOYSTICK (bottom-left) — analog movement */
  .joystick {
    position: absolute;
    left: calc(24px + env(safe-area-inset-left, 0px));
    bottom: calc(40px + env(safe-area-inset-bottom, 0px));
    width: 130px;
    height: 130px;
    border-radius: 50%;
    background: rgba(15, 11, 8, 0.55);
    border: 2px solid rgba(201, 161, 74, 0.65);
    pointer-events: auto;
    touch-action: none;
    -webkit-tap-highlight-color: transparent;
    box-shadow: 0 4px 0 rgba(0,0,0,0.3), inset 0 0 30px rgba(0,0,0,0.35);
  }
  .joystick .knob {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 60px;
    height: 60px;
    margin-left: -30px;
    margin-top: -30px;
    border-radius: 50%;
    background: rgba(178, 58, 58, 0.9);
    border: 2px solid var(--gold);
    box-shadow: 0 3px 0 rgba(0,0,0,0.4);
    transition: background 0.08s;
    pointer-events: none;
    will-change: transform;
  }
  .joystick.active .knob { background: var(--red); }

  /* Primary ACT button — BIG round button at bottom-right, mirroring the
     joystick at bottom-left. This is the one the thumb lives on. */
  .mc-action {
    right: calc(24px + env(safe-area-inset-right, 0px));
    bottom: calc(40px + env(safe-area-inset-bottom, 0px));
    left: auto;
    top: auto;
    width: 118px;
    height: 118px;
    border-radius: 50%;
    font-size: 19px;
    letter-spacing: 2px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(178, 58, 58, 0.88);
    border-color: var(--gold);
    border-width: 3px;
    color: var(--paper);
    font-weight: 800;
  }
  .mc-action:active, .mc-action.pressed {
    background: var(--redDk, #7a1f1f);
    transform: translateY(3px);
  }

  /* PAUSE — small pill at top-left on every touch device. The rules
     screen tells the player to tap it, so it must actually be visible
     on phone-class devices too; previously the touch-rules text and
     the CSS contradicted each other. */
  .mc-esc {
    top: calc(4px + env(safe-area-inset-top, 0px));
    left: calc(8px + env(safe-area-inset-left, 0px));
    right: auto;
    width: 56px;
    height: 26px;
    font-size: 10px;
    letter-spacing: 1px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
    opacity: 0.8;
  }
  /* Action hint overlays YAMAMORI on every device when a threat is in reach. */

  /* Portrait-rotate hint */
  #portrait-hint {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 999;
    background: #0f0b08;
    color: var(--paper);
    align-items: center;
    justify-content: center;
    flex-direction: column;
    text-align: center;
    padding: 30px;
    font-family: -apple-system, system-ui, sans-serif;
  }
  /* CSS-drawn phone (no emoji) — a gold-outlined body with an inset
     screen; the rotate-anim tips it landscape and back. */
  #portrait-hint .ph-icon {
    width: 46px;
    height: 80px;
    margin: 0 auto 22px;
    border: 4px solid var(--gold);
    border-radius: 10px;
    background: rgba(201,161,74,0.10);
    position: relative;
    animation: rotate-anim 2.5s ease-in-out infinite;
  }
  #portrait-hint .ph-icon::before {
    content: "";
    position: absolute;
    inset: 8px 6px 12px;
    border-radius: 3px;
    background: rgba(201,161,74,0.22);
  }
  #portrait-hint .ph-icon::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: 3px;
    width: 12px;
    height: 3px;
    margin-left: -6px;
    border-radius: 2px;
    background: var(--gold);
  }
  #portrait-hint h2 { font-size: 26px; margin-bottom: 12px; color: var(--gold); letter-spacing: 1px; }
  #portrait-hint p { font-size: 16px; color: var(--paper); line-height: 1.7; max-width: 360px; }
  #portrait-hint .ph-sub { font-size: 13px; color: #9b8a6a; margin-top: 18px; }
  @keyframes rotate-anim {
    0%, 40% { transform: rotate(0deg); }
    50%, 90% { transform: rotate(-90deg); }
    100% { transform: rotate(0deg); }
  }

  .bucket-icon {
    width: 12px;
    height: 16px;
    background: var(--bucket, #6a4a2a);
    position: relative;
    display: inline-block;
    border-top: 2px solid #3a2212;
  }
  .bucket-icon .fill {
    position: absolute;
    left: 1px;
    right: 1px;
    bottom: 1px;
    background: #4b9edc;
    transition: height 0.15s;
  }

  /* Three-segment water bar (bottom-right of HUD). One segment per bucket
     charge; fills blue when full, darkens when spent. The "WATER" label
     tells players what the bar represents. When the bucket is empty we add
     .empty to strobe the whole bar red so the player knows to go refill. */
  .water-bar { display: inline-flex; align-items: center; gap: 5px; }
  .water-lbl { color: #9fc3d8; font-weight: 700; letter-spacing: 1.5px; margin-right: 3px; }
  .water-seg {
    display: inline-block;
    width: 24px;
    height: 14px;
    background: rgba(15, 11, 8, 0.55);
    border: 1.5px solid var(--gold);
    border-radius: 2px;
    transition: background 0.15s;
  }
  .water-seg.filled { background: #4b9edc; box-shadow: inset 0 -3px 0 rgba(255,255,255,0.22); }

  /* When bucket === 0, the WATER label AND every segment box flash.
     The boxes stay HOLLOW — just the outline alternates red ↔ gold
     with a soft pulse so it reads as an alarm rather than filled
     red bars. */
  @keyframes water-lbl-flash {
    0%, 49%   { color: #ff3b3b; text-shadow: 0 0 4px rgba(255,59,59,0.55); }
    50%, 100% { color: #c9a14a; text-shadow: 0 0 3px rgba(201,161,74,0.45); }
  }
  @keyframes water-seg-flash {
    0%, 49%   {
      background: transparent;
      border-color: #ff3b3b;
      box-shadow: 0 0 6px rgba(255,59,59,0.65);
      transform: scale(1.04);
    }
    50%, 100% {
      background: transparent;
      border-color: #c9a14a;
      box-shadow: none;
      transform: scale(1);
    }
  }
  .water-bar.empty .water-lbl { animation: water-lbl-flash 0.5s steps(2) infinite; }
  .water-bar.empty .water-seg { animation: water-seg-flash 0.5s steps(2) infinite; }

  /* In-game HTML overlays — crisp text.
     Desktop: action hint flashes just UNDER the top bar, centre.
     Mobile (body.touch below): floats on the right side above the big ACT
     button so the player's thumb sees it without covering play. */
  @keyframes action-alert-flash {
    0%, 49%   { opacity: 1;   box-shadow: 0 0 10px rgba(255, 230, 138, 0.55); }
    50%, 100% { opacity: 0.55; box-shadow: none; }
  }
  .action-hint {
    position: absolute;
    top: 50px;
    left: 50%;
    transform: translateX(-50%);
    animation: action-alert-flash 0.65s ease-in-out infinite;
    z-index: 6;
    background: rgba(15,11,8,0.94);
    border-top: 2px solid var(--gold);
    color: #ffe68a;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    font-weight: 700;
    font-size: 13px;
    letter-spacing: 0.5px;
    padding: 6px 12px;
    pointer-events: none;
  }
  .action-hint.hidden { display: none; animation: none; }

  /* On touch, the hint tucks under the TIME readout in the top-right so it
     doesn't cover any gameplay area. */
  body.touch .action-hint {
    top: calc(52px + env(safe-area-inset-top, 0px));
    left: auto;
    right: calc(12px + env(safe-area-inset-right, 0px));
    transform: none;
    bottom: auto;
  }

  .toast {
    /* Desktop: flashes just under the top bar (same band as the hint).
       Touch: flashes on the right over the ACT button. */
    position: absolute;
    top: 50px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 7;
    animation: action-alert-flash 0.65s ease-in-out infinite;
    background: rgba(15,11,8,0.92);
    color: var(--paper);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    font-weight: 700;
    font-size: 14px;
    padding: 6px 16px;
    border: 1px solid var(--gold);
    border-radius: 2px;
    pointer-events: none;
    text-align: center;
    transition: opacity 0.15s;
    box-shadow: 0 3px 0 rgba(0,0,0,0.35);
  }
  .toast.hidden { display: none; animation: none; }
  .toast.good { color: #9fd06c; border-color: #9fd06c; }
  .toast.bad  { color: #ff8080; border-color: #b33a3a; }
  body.touch .toast {
    top: calc(52px + env(safe-area-inset-top, 0px));
    left: auto;
    right: calc(12px + env(safe-area-inset-right, 0px));
    transform: none;
    bottom: auto;
  }

  /* Minimap — only on touch. Top-LEFT corner (above the joystick), sized
     big enough to read on a phone. Shows river, player (yellow), fires
     (strobing red), poachers (black), scrolls (gold). */
  .minimap {
    position: absolute;
    top: calc(50px + env(safe-area-inset-top, 0px));
    left: calc(12px + env(safe-area-inset-left, 0px));
    right: auto;
    width: 150px;
    height: 100px;
    z-index: 5;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    border: 2px solid var(--gold);
    background: rgba(15, 11, 8, 0.72);
    box-shadow: 0 2px 0 rgba(0,0,0,0.4);
    display: none;
  }
  /* The minimap is retired — the whole board is on screen now, so
     an overview map is redundant. Kept in the DOM but never shown. */
  .minimap.hidden { display: none !important; }

  /* Cycle ambient tint — a soft color wash overlaid on the canvas that
     shifts with the active 50-year cycle. The tint sits ABOVE the
     canvas but BELOW the HUD bars / overlays so the timeline + banners
     stay punchy. mix-blend-mode keeps the underlying pixel art visible
     while still feeling the mood shift. */
  .cycle-tint {
    position: absolute;
    /* Covers exactly the game canvas — below the HUD bar + timeline
       (74px), above the bottom bar (38px). */
    top: 74px;
    left: 0;
    right: 0;
    bottom: 38px;
    z-index: 3;
    pointer-events: none;
    mix-blend-mode: multiply;
    opacity: 0.4;
    background: #d96030;  /* default cycle-1 dusk */
    /* Slow generation-crossfade between cycles — the mood eases
       across rather than snapping when the player advances. */
    transition: background 2.4s cubic-bezier(0.45, 0.05, 0.55, 0.95),
                opacity    2.4s cubic-bezier(0.45, 0.05, 0.55, 0.95);
  }
  .cycle-tint.hidden { display: none; }
  /* Each cycle has its OWN distinct light, so the four chapters
     read as separate, well-defined eras at a glance. */
  .cycle-tint.c-0 { background: #d9542a; opacity: 0.58; }  /* 1657 Meireki — dusk + smoke, hot orange */
  .cycle-tint.c-1 { background: #eadfb0; opacity: 0.30; }  /* 1707 Hōei — pale, hopeful planting-morning light */
  .cycle-tint.c-2 { background: #ffbc3a; opacity: 0.40; }  /* 1757 Hōreki — warm afternoon gold */
  .cycle-tint.c-3 { background: #6a7e9a; opacity: 0.56; }  /* 1807 Bunka — cool, overcast, late */
  @media (max-width: 860px), (pointer: coarse) {
    .cycle-tint { top: calc(78px + env(safe-area-inset-top, 0px)); bottom: calc(38px + env(safe-area-inset-bottom, 0px)); }
  }

  /* 200-year timeline strip — an inked-scroll ribbon under the top
     HUD bar. The rail reads as a sumi brush stroke; each cycle is
     a seal-mark dot (hollow = still to come, green = lived through,
     gold = the present). Era kanji sits above as the hero label,
     the year a small caption below. */
  .hud-timeline {
    position: absolute;
    left: 0;
    right: 0;
    top: 40px;          /* matches .hud-top desktop height */
    height: 34px;
    z-index: 5;
    /* Solid opaque fill — NOT translucent, so the moving game map
       can't bleed through and smear the strip. */
    background: #100c08;
    border-bottom: 2px solid var(--gold);
    pointer-events: none;
    box-sizing: border-box;
    overflow: visible;
  }
  .hud-timeline.hidden { display: none; }
  /* The rail — a soft ink brush stroke fading at both ends. */
  .hud-timeline .tl-rail {
    position: absolute;
    left: 8%;
    right: 8%;
    top: 50%;
    height: 2px;
    background: linear-gradient(90deg,
      rgba(160,140,100,0) 0%, rgba(160,140,100,0.55) 2.5%,
      rgba(160,140,100,0.55) 97.5%, rgba(160,140,100,0) 100%);
    transform: translateY(-50%);
  }
  /* Progress — an ink-and-gold wash that fills the rail toward the
     present cycle, glowing softly at its leading edge. */
  .hud-timeline .tl-progress {
    position: absolute;
    left: 8%;
    top: 50%;
    width: 0%;
    height: 3px;
    background: linear-gradient(90deg, #4e7a32 0%, #6ba04c 55%, #c9a14a 100%);
    transform: translateY(-50%);
    box-shadow: 0 0 7px rgba(201,161,74,0.6);
    transition: width 0.7s cubic-bezier(0.18, 0.89, 0.32, 1.15);
    border-radius: 0 2px 2px 0;
  }
  /* Each tick is absolutely positioned along the rail. */
  .hud-timeline .tl-tick {
    position: absolute;
    top: 0;
    bottom: 0;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    pointer-events: none;
  }
  /* Seal-mark dot — future cycles are a hollow ink ring; reached
     cycles fill in. */
  .hud-timeline .tl-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: transparent;
    border: 1.5px solid #6a5a3a;
    box-shadow: 0 1px 2px rgba(0,0,0,0.6);
    transition: background 0.45s ease, border-color 0.45s ease,
                width 0.3s, height 0.3s, box-shadow 0.45s;
  }
  .hud-timeline .tl-yr {
    position: absolute;
    top: 12px;
    font-size: 8px;
    font-weight: 700;
    color: #9b8a6a;
    letter-spacing: 1.5px;
    font-family: "Courier New", monospace;
    white-space: nowrap;
    text-shadow: 0 1px 0 #000;   /* crisp, no blur */
    transition: color 0.45s ease;
  }
  /* Year label sits BELOW the dot. The original styling (bottom: 11px,
     font-size: 12px, letter-spacing: 3px) was tuned for 2-character
     era kanji (明暦 / 宝永 / 宝暦 / 文化) — those overlapped the dot
     too, but the dot peeked through their negative space so it read
     OK. Four arabic digits with that wide a letter-spacing stack
     solid across the dot, which is what users are seeing. Fix:
     drop letter-spacing and pin the label to the bottom edge so the
     dot (including its 13px active size + pulse glow) has clear air
     above the text. */
  .hud-timeline .tl-era {
    position: absolute;
    bottom: 1px;
    font-size: 10px;
    line-height: 1;
    font-weight: 800;
    color: #7a6d4a;
    letter-spacing: 0.5px;
    white-space: nowrap;
    text-shadow: 0 1px 0 #000;   /* crisp, no blur */
    transition: color 0.45s ease, transform 0.3s ease;
  }
  /* Past — lived through: green ink seal, label settled. */
  .hud-timeline .tl-tick.past .tl-dot { background: #6ba04c; border-color: #3a5a22; }
  .hud-timeline .tl-tick.past .tl-era { color: #6ba04c; }
  .hud-timeline .tl-tick.past .tl-yr  { color: #8aa86a; }
  /* Active — the present chapter: a gold seal, pulsing, the era
     kanji lifted slightly and brightened. */
  .hud-timeline .tl-tick.active .tl-dot {
    background: #ffd860;
    border-color: #8a5a1a;
    width: 13px;
    height: 13px;
    animation: tlActivePulse 1.7s ease-in-out infinite;
  }
  .hud-timeline .tl-tick.active .tl-era {
    color: #ffd860;
    transform: scale(1.12);
  }
  .hud-timeline .tl-tick.active .tl-yr { color: #ffd860; }
  @keyframes tlActivePulse {
    0%, 100% { box-shadow: 0 0 5px #ffd860, 0 0 12px rgba(255,216,96,0.55), 0 1px 2px rgba(0,0,0,0.6); }
    50%      { box-shadow: 0 0 9px #ffd860, 0 0 20px rgba(255,216,96,0.85), 0 1px 2px rgba(0,0,0,0.6); }
  }
  @media (max-width: 860px), (pointer: coarse) {
    .hud-timeline {
      top: calc(44px + env(safe-area-inset-top, 0px));
      height: 46px;
    }
    .hud-timeline .tl-yr  { bottom: 5px; font-size: 7px; }
    /* Mobile: same below-the-dot placement as desktop, slightly larger
       text to stay legible at touch viewing distance. Tight
       letter-spacing because four arabic digits need to read as one
       word, not as four floating numerals. */
    .hud-timeline .tl-era { bottom: 3px; top: auto; font-size: 11px; letter-spacing: 0.5px; }
    .hud-timeline .tl-dot { width: 8px; height: 8px; }
    .hud-timeline .tl-tick.active .tl-dot { width: 11px; height: 11px; }
  }

  /* Progressive reveal for the start page — when the title screen
     shows, its panel sections fade and rise into place one after
     another, like a scroll being unrolled. Gated on :not(.hidden)
     so it replays cleanly each time the player returns to the
     title. ~1.5s for the full sequence. */
  @keyframes titleReveal {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  #title-screen:not(.hidden) .paper-panel > * {
    animation: titleReveal 0.55s ease-out backwards;
  }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(1)  { animation-delay: 0.05s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(2)  { animation-delay: 0.16s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(3)  { animation-delay: 0.27s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(4)  { animation-delay: 0.38s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(5)  { animation-delay: 0.49s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(6)  { animation-delay: 0.60s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(7)  { animation-delay: 0.71s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(8)  { animation-delay: 0.82s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(9)  { animation-delay: 0.93s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(10) { animation-delay: 1.04s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(11) { animation-delay: 1.15s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(12) { animation-delay: 1.26s; }
  #title-screen:not(.hidden) .paper-panel > *:nth-child(n+13) { animation-delay: 1.37s; }
  /* The two red rules on the panel are ::before/::after and are
     not children — they don't animate, which is fine. */
  /* Reduced-motion: full pass.
     Honours the OS-level "reduce motion" preference. We don't kill ALL
     animation — the chapter banner and goal slide are essential
     storytelling beats — but we cut their durations to a single tick
     so they cross-fade rather than zoom/stamp. The kanji rotate, the
     timeline tick pulse, the action-alert flash, the water-empty
     strobe, the lost-counter pulse, and the title-screen panel reveal
     all become no-ops. The JS side (particle spawn rate, tutorial
     ring, near-threat ring, river arrow) keys off the same matchMedia
     query, so the entire game calms together. */
  @media (prefers-reduced-motion: reduce) {
    #title-screen:not(.hidden) .paper-panel > *,
    .kanji-big,
    .tl-tick.active::after,
    #action-hint,
    #hud-bucket.empty .water-seg,
    #hud-bucket.empty .water-lbl,
    #hud-lost,
    #season-banner,
    #goal-banner {
      animation: none !important;
    }
    .season-banner.show { opacity: 1; }
    *, *::before, *::after {
      transition-duration: 0.001ms !important;
    }
  }

  .season-banner {
    position: absolute;
    top: 50%;
    left: 0;
    right: 0;
    transform: translateY(-50%);
    z-index: 6;
    background: rgba(15,11,8,0.94);
    border-top: 3px solid var(--gold);
    border-bottom: 3px solid var(--gold);
    color: var(--paper);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    font-weight: 800;
    font-size: 26px;
    letter-spacing: 4px;
    padding: 22px 20px;
    text-align: center;
    pointer-events: none;
    transition: opacity 0.4s;
    box-shadow:
      0 -16px 24px rgba(0,0,0,0.35),
      0  16px 24px rgba(0,0,0,0.35);
    text-shadow: 0 2px 6px rgba(0,0,0,0.7);
  }
  .season-banner.hidden { display: none; }
  /* Ink-stamp arrival: a quick zoom-down from larger-than-target with
     gold light flaring through, then settle. Replays each cycle when
     the banner text is updated and the .show class is toggled. */
  @keyframes chapterStamp {
    0%   { transform: translateY(-50%) scale(1.55); letter-spacing: 18px; opacity: 0; filter: blur(2px); }
    35%  { transform: translateY(-50%) scale(0.96); letter-spacing: 2px;  opacity: 1; filter: blur(0); }
    55%  { transform: translateY(-50%) scale(1.02); letter-spacing: 5px; }
    100% { transform: translateY(-50%) scale(1);    letter-spacing: 4px; opacity: 1; filter: blur(0); }
  }
  .season-banner:not(.hidden) {
    animation: chapterStamp 0.85s cubic-bezier(0.18, 0.89, 0.32, 1.28);
  }
  .season-banner .wave-n          { color: var(--gold); margin-right: 12px; }
  .season-banner .kanji-big-inline { color: var(--red); margin: 0 6px; }

  /* Goal sub-banner — slides in just below the chapter banner with
     the current chapter's gameplay objective so the player knows
     what to focus on, not just what year it is. Slightly smaller,
     paper-yellow text on the same dark stripe. */
  .goal-banner {
    position: absolute;
    top: calc(50% + 50px);
    left: 0;
    right: 0;
    z-index: 6;
    background: rgba(15,11,8,0.92);
    border-top: 1px solid rgba(201,161,74,0.65);
    border-bottom: 1px solid rgba(201,161,74,0.65);
    color: var(--paper);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    font-weight: 600;
    font-size: 14px;
    letter-spacing: 1.5px;
    padding: 10px 20px;
    text-align: center;
    pointer-events: none;
    transition: opacity 0.4s;
    box-shadow:
      0 -10px 18px rgba(0,0,0,0.25),
      0  10px 18px rgba(0,0,0,0.25);
    text-shadow: 0 1px 3px rgba(0,0,0,0.7);
  }
  .goal-banner.hidden { display: none; }
  .goal-banner .glabel { color: var(--gold); margin-right: 10px; letter-spacing: 3px; font-weight: 800; }
  .goal-banner .gtext  { color: #e8d9b0; }
  .goal-banner .gtext b { color: #ffd860; font-weight: 700; }
  @keyframes goalSlide {
    0%   { opacity: 0; transform: translateY(-8px); }
    100% { opacity: 1; transform: translateY(0); }
  }
  .goal-banner:not(.hidden) {
    animation: goalSlide 0.55s ease-out;
  }
  @media (max-width: 860px), (pointer: coarse) {
    .goal-banner { font-size: 12px; padding: 8px 14px; top: calc(50% + 42px); }
    .goal-banner .glabel { letter-spacing: 2px; }
  }

  .btn-row {
    display: flex;
    gap: 12px;
    justify-content: center;
    flex-wrap: wrap;
  }

  .glossary {
    background: rgba(42,31,20,0.05);
    border: 1px dashed var(--ink);
    padding: 12px 16px;
    font-size: 12px;
    line-height: 1.7;
    text-align: left;
    margin: 12px 0;
    column-count: 2;
    column-gap: 24px;
  }
  .glossary .term { color: var(--red); font-weight: bold; }

  /* "Edo Rebuilds" timeline strip on the intro screen — sourced bullets
     pulled from the Tokyo Metropolitan Library + Diamond ch.9 so the
     player sees how the city grew alongside the forest before they
     ever pick up the bucket. */
  .rebuild-strip {
    margin: 14px 0;
    padding: 12px 16px;
    background: rgba(60,110,42,0.06);
    border: 1px dashed var(--green);
    text-align: left;
  }
  .rebuild-title {
    font-size: 12px;
    color: var(--green);
    letter-spacing: 3px;
    font-weight: 800;
    margin-bottom: 8px;
    text-align: center;
  }
  .rebuild-list {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 12px;
    line-height: 1.6;
    color: var(--ink);
  }
  .rebuild-list li {
    padding: 4px 0 4px 14px;
    border-bottom: 1px dashed rgba(42,31,20,0.18);
    position: relative;
  }
  .rebuild-list li::before {
    content: "·";
    position: absolute;
    left: 4px;
    color: var(--green);
    font-weight: 800;
  }
  .rebuild-list li:last-child { border-bottom: none; }
  .rebuild-list li b { color: var(--red); }
  .rebuild-cite {
    margin-top: 6px;
    font-size: 10px;
    color: var(--ink2);
    font-style: italic;
    text-align: right;
  }

  .fact-strip {
    margin-top: 12px;
    padding: 10px 12px;
    background: rgba(178, 58, 58, 0.08);
    border-left: 3px solid var(--red);
    font-size: 12px;
    line-height: 1.6;
    text-align: left;
    font-style: italic;
    color: var(--ink);
  }

  .seal {
    display: inline-block;
    color: var(--paper);
    background: var(--red);
    padding: 4px 10px;
    font-size: 11px;
    letter-spacing: 3px;
    margin-right: 6px;
    box-shadow: 2px 2px 0 var(--ink);
  }

/* Responsive geometry and accessible input. Keep the original paper, ink,
   red, gold, typography, artwork, and screen order above. */
:root {
  --top: calc(44px + env(safe-area-inset-top, 0px));
  --bottom: calc(38px + env(safe-area-inset-bottom, 0px));
  --dock: 0px;
}
.hidden { display: none !important; }
button:focus-visible, summary:focus-visible, a:focus-visible, canvas:focus-visible {
  outline: 3px solid var(--gold); outline-offset: 3px;
}
#game-wrap { max-width: 100%; overflow: hidden; }
canvas#game {
  top: calc(var(--top) + 34px);
  height: calc(100% - var(--top) - 34px - var(--bottom) - var(--dock));
  object-fit: fill;
}
.overlay { padding-top: max(8px, env(safe-area-inset-top)); }
.paper-panel { flex-shrink: 0; max-width: min(780px, 100%); }
#pause-screen.overlay { left: 0; right: 0; }
.hud-top { height: var(--top); padding-top: env(safe-area-inset-top); }
.hud-bottom { height: var(--bottom); padding-bottom: env(safe-area-inset-bottom); }
.hud-top .hud-slot-right { order: 3; }
.hud-pause {
  order: 4; flex-shrink: 0; width: 40px; height: 40px; margin-left: 12px;
  pointer-events: auto; color: var(--gold); background: #0f0b08;
  border: 1px solid var(--gold); font: bold 20px 'Courier New', monospace;
  cursor: pointer; touch-action: manipulation;
}
.hud-timeline { top: var(--top); height: 34px; }
.cycle-tint { top: calc(var(--top) + 34px); bottom: calc(var(--bottom) + var(--dock)); }
.minimap:not(.hidden) {
  display: block; width: 96px; height: 64px; top: calc(var(--top) + 46px);
  right: 12px; left: auto; pointer-events: none;
}
.patrol-guide {
  position: absolute; top: calc(var(--top) + 46px); left: 12px; z-index: 4;
  max-width: min(350px, calc(100% - 132px)); padding: 8px 10px;
  color: var(--paper); background: #0f0b08e8; border-left: 2px solid var(--gold);
  text-align: left; pointer-events: none;
}
.patrol-guide span { display: block; color: var(--gold); font-size: 9px; letter-spacing: 1px; }
.patrol-guide b { display: block; margin-top: 5px; font-size: 12px; }
.patrol-guide small { display: block; margin-top: 5px; font-size: 10px; line-height: 1.5; }
.action-hint, body.touch .action-hint {
  top: auto; bottom: calc(var(--bottom) + var(--dock) + 10px);
  left: 50%; right: auto; transform: translateX(-50%); max-width: 95%;
  white-space: nowrap; pointer-events: none;
}
.toast, body.touch .toast {
  top: auto; bottom: calc(var(--bottom) + var(--dock) + 50px);
  left: 50%; right: auto; transform: translateX(-50%); max-width: 90%;
  pointer-events: none;
}
.joystick, .mc-action {
  bottom: calc(var(--bottom) + 16px); width: 100px; height: 100px;
}
.joystick { left: max(18px, env(safe-area-inset-left)); }
.mc-action { right: max(18px, env(safe-area-inset-right)); font-size: 16px; }
.mc-action.ready { box-shadow: 0 0 0 4px #c9a14a44; }
.joystick .knob { width: 46px; height: 46px; margin: -23px; }
.hud-note { display: none; }
.run-seed { color: var(--ink2); font-size: 10px; margin-top: 6px; }
@media (max-width: 600px) {
  .paper-panel { width: 100%; padding: 24px 20px; max-height: calc(100dvh - 24px); }
  h1 { font-size: clamp(26px, 8vw, 34px); letter-spacing: 2px; overflow-wrap: anywhere; }
  .controls-box .ctl-sub { white-space: normal; margin-left: 0; }
  .controls-box .ctl-row { line-height: 1.8; margin: 10px 0; }
  .infographic-grid { display: grid; }
  .infographic-panel { max-width: 100%; height: auto; }
  .hud-top .hud-slot-center { display: none; }
  .hud-bar { padding-left: 12px; padding-right: 12px; gap: 8px; }
  .hud-bottom .hud-slot, #hud-lost { font-size: 11px; }
  #hud-buff { position: absolute; bottom: calc(var(--bottom) + var(--dock) + 8px); left: 12px; }
  .patrol-guide b { font-size: 11px; }
  .patrol-guide small { font-size: 9px; }
}
@media (orientation: portrait) {
  body.touch { --dock: 132px; }
  body.touch .mobile-controls::before {
    content: ''; position: absolute; left: 0; right: 0; bottom: var(--bottom);
    height: var(--dock); background: #0f0b08; border-top: 1px solid var(--gold);
  }
}
@media (orientation: landscape) and (max-height: 520px) {
  :root { --bottom: calc(36px + env(safe-area-inset-bottom, 0px)); }
  .joystick, .mc-action { width: 86px; height: 86px; bottom: calc(var(--bottom) + 12px); }
  .patrol-guide { max-width: 300px; padding: 6px 10px; }
  .patrol-guide small { display: none; }
  .patrol-guide b { font-size: 10px; }
  .paper-panel { max-height: calc(100dvh - 16px); }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
