/* LAST PACK — mobile portrait UI. Palette from GDD v1.0 §15.2. */
:root {
  --canvas: #2B2923;
  --canvas-deep: #14140f;
  --iron: #5C3D2E;
  --amber: #C5A43B;
  --green: #66755B;
  --teal: #4F7472;
  --bleed: #8E2D2D;
  --dust: #B8B0A0;
  --ink: #EDE6D6;
  --muted: #9C947F;
  --line: rgba(197, 164, 59, .22);
  --line-soft: rgba(184, 176, 160, .14);
  --panel: rgba(20, 20, 15, .82);
  --panel-2: rgba(33, 32, 25, .9);
  --radius: 10px;
  /* --text-scale is the player's A / A+ / A++ setting (1 / 1.15 / 1.3),
     written by app.applySettings(). --type-scale is what every font-size
     actually reads: the setting times a global boost, because 14px base
     tested too small on a real phone for players over 40. */
  --text-scale: 1;
  --type-scale: calc(var(--text-scale) * 1.15);
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --font: "Pretendard", "Apple SD Gothic Neo", "Malgun Gothic", system-ui, -apple-system, sans-serif;
  --mono: ui-monospace, "SF Mono", Consolas, monospace;
}

*, *::before, *::after {
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
  /* iOS keeps double-tap-to-zoom armed on a zoomable viewport, and this game is
     built on repeat taps of ~40px targets (grid cells, speed buttons, offer
     cards). `manipulation` is `pan-x pan-y pinch-zoom`, so scrolling and pinch
     still work — only the double-tap gesture goes away. */
  touch-action: manipulation;
  /* Long-pressing item art otherwise raises the iOS Save Image sheet over the
     board, and swallows the pending tap. */
  -webkit-touch-callout: none;
}
/* The UA sheet's `[hidden] { display: none }` loses to any author `display`
   rule, and several panels here are `display: grid` — without this the title
   menu, the debrief detail and the score breakdown are all permanently open. */
[hidden] { display: none !important; }
html, body { height: 100%; margin: 0; }
body {
  background: var(--canvas-deep);
  color: var(--ink);
  font-family: var(--font);
  font-size: calc(14px * var(--type-scale));
  line-height: 1.45;
  overflow: hidden;
  overscroll-behavior: none;
  -webkit-font-smoothing: antialiased;
}
body.reduce-motion *, body.reduce-motion *::before, body.reduce-motion *::after {
  animation-duration: .001ms !important; transition-duration: .001ms !important;
}
/* Unprefixed user-select only landed in Safari 17, so 16.x needs the prefix or
   a long press raises the text-selection magnifier over item names and badges. */
img { max-width: 100%; display: block; -webkit-user-select: none; user-select: none; }
button, .cell, .pack-item, .main-tab, .sub-tab, .home-tile, .stage-node, .zone-node {
  -webkit-user-select: none; user-select: none;
}
button { font: inherit; color: inherit; cursor: pointer; }
h1, h2, h3, h4 { margin: 0; font-weight: 700; letter-spacing: -.01em; }
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
dl, dd, dt { margin: 0; }

.grain {
  position: fixed; inset: 0; pointer-events: none; z-index: 60; opacity: .05;
  background-image: repeating-linear-gradient(0deg, rgba(255,255,255,.6) 0 1px, transparent 1px 3px);
  mix-blend-mode: overlay;
}
.frame {
  position: relative; height: 100dvh; width: 100%;
  max-width: 480px; margin: 0 auto; overflow: hidden;
  background: radial-gradient(120% 80% at 50% 0%, #24231b 0%, #0f0f0b 70%);
  box-shadow: 0 0 0 1px rgba(0,0,0,.6);
}
.screen {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  padding-top: var(--safe-t); padding-bottom: var(--safe-b);
  overflow: hidden;
}
.code { font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); letter-spacing: .14em; text-transform: uppercase; color: var(--amber); opacity: .85; }
.note { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); line-height: 1.5; }
.warn { font-size: calc(11.5px * var(--type-scale)); color: #E5B25A; background: rgba(197,164,59,.1); border: 1px solid rgba(197,164,59,.3); border-radius: 8px; padding: 7px 10px; }
.sub { font-size: calc(12px * var(--type-scale)); color: var(--dust); letter-spacing: .04em; margin: 14px 0 8px; }
.empty { color: var(--muted); font-size: calc(12px * var(--type-scale)); text-align: center; padding: 28px 12px; }

/* ---------- controls ---------- */
.btn {
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  min-height: 44px; padding: 9px 14px; border-radius: var(--radius);
  border: 1px solid var(--line); background: rgba(48,45,34,.75);
  font-weight: 600; letter-spacing: .01em; transition: transform .12s, background .16s, border-color .16s;
}
.btn small { font-weight: 400; font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .38; cursor: not-allowed; }
/* Buttons are stamped metal plates, 9-sliced so the rivets stay in the corners
   at any size. The gradient stays underneath as the fallback if the image is
   still loading — and as the colour the text contrast was chosen against. */
.btn.primary {
  background: linear-gradient(180deg, #d8b449, #a8892f); border-color: #e0c069; color: #201c10;
  border-width: 16px; border-style: solid;
  border-image: url('./assets/art/ui/btn-primary.webp') 84 fill / 16px / 0 stretch;
  text-shadow: 0 1px 0 rgba(255,244,205,.45);
}
.btn.primary small { color: rgba(32,28,16,.8); text-shadow: none; }
.btn.ghost {
  background: rgba(255,255,255,.04);
  border-width: 16px; border-style: solid;
  border-image: url('./assets/art/ui/btn-ghost.webp') 84 fill / 16px / 0 stretch;
}
/* The plate art carries its own edge, so the padding has to come off the border
   box rather than stacking on top of a 16px border. */
.btn.primary, .btn.ghost { padding: 2px 4px; }
.btn.primary.small, .btn.ghost.small { border-width: 12px; border-image-width: 12px; padding: 0 2px; }
.btn.danger { border-color: rgba(142,45,45,.7); background: rgba(142,45,45,.22); color: #f0b9b9; }
.btn.wide { width: 100%; }
.btn.small { min-height: 44px; padding: 6px 11px; font-size: calc(12px * var(--type-scale)); border-radius: 8px; }
.text-btn { background: none; border: 0; color: var(--amber); font-size: calc(12px * var(--type-scale)); min-height: 44px; padding: 8px 6px; text-decoration: underline; text-underline-offset: 3px; }
.icon-btn {
  width: 44px; height: 44px; border-radius: 11px; border: 1px solid var(--line-soft);
  background: rgba(255,255,255,.05); display: grid; place-items: center; font-size: calc(20px * var(--type-scale)); line-height: 1;
}
.icon-btn.back { font-size: calc(26px * var(--type-scale)); }
kbd { font: 10px var(--mono); border: 1px solid var(--line-soft); border-radius: 4px; padding: 1px 4px; opacity: .7; }
.chip { display: inline-flex; align-items: center; gap: 4px; padding: 3px 8px; border-radius: 999px; border: 1px solid var(--line-soft); background: rgba(255,255,255,.05); font-size: calc(11.5px * var(--type-scale)); color: var(--dust); }
.chip.sit { border-color: rgba(79,116,114,.5); color: #a9cfcb; }
.bar { height: 5px; border-radius: 3px; background: rgba(255,255,255,.09); overflow: hidden; }
.bar > b { display: block; height: 100%; background: linear-gradient(90deg, var(--green), var(--amber)); transition: width .3s; }
.seg { display: inline-flex; gap: 4px; }
.seg-btn { min-width: 46px; min-height: 44px; border-radius: 8px; border: 1px solid var(--line-soft); background: rgba(255,255,255,.04); font-size: calc(12px * var(--type-scale)); }
.seg-btn.on { background: rgba(197,164,59,.24); border-color: var(--amber); color: #f0dfa8; }
.seg.small .seg-btn { min-width: 42px; min-height: 40px; }
.toggle { min-width: 66px; min-height: 44px; border-radius: 999px; border: 1px solid var(--line-soft); background: rgba(255,255,255,.05); font-size: calc(11.5px * var(--type-scale)); }
.toggle.on { background: rgba(102,117,91,.3); border-color: var(--green); color: #cfe0c0; }
.pager { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 14px 14px; }
.pager-label { font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
/* Full-bleed backdrops are absolutely positioned, so they paint above — and
   swallow taps on — any static in-flow sibling that comes later in the DOM.
   That is what hid the stage brief's 출동 button behind .brief-veil. Pin the
   backdrops to layer 0 and make them untappable; every foreground layer on
   these screens already carries its own position:relative. */
.brief-bg, .brief-veil, .result-bg, .result-veil,
.home-bg, .home-veil, .title-art, .title-veil { z-index: 0; pointer-events: none; }
.btn.wide.sticky-cta { width: auto; align-self: stretch; margin: 0 14px 14px; flex: 0 0 auto; position: relative; z-index: 2; }

/* ---------- shape block ---------- */
.shape-block { display: grid; grid-template-columns: repeat(var(--sw), 1fr); grid-template-rows: repeat(var(--sh), 1fr); gap: 1.5px; }
.shape-block i { width: 7px; height: 7px; border-radius: 1.5px; background: transparent; }
.shape-block i.on { background: var(--dust); opacity: .85; }
.shape-block.mini i { width: 6px; height: 6px; }
.shape-block.tiny i { width: 4px; height: 4px; }
.shape-block.big i { width: 15px; height: 15px; border-radius: 2px; }
.shape-block.big i.on { background: var(--amber); }

/* ---------- toast / modals ---------- */
.toast {
  position: fixed; left: 50%; bottom: calc(84px + var(--safe-b)); transform: translate(-50%, 12px);
  max-width: 88vw; padding: 10px 16px; border-radius: 999px; z-index: 90;
  background: rgba(18,18,13,.96); border: 1px solid var(--line); color: var(--ink);
  font-size: calc(12px * var(--type-scale)); opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.bad { border-color: rgba(142,45,45,.8); color: #f2c3c3; }
.modal-layer {
  position: fixed; inset: 0; z-index: 95; display: grid; place-items: center;
  background: rgba(6,6,4,.72); backdrop-filter: blur(3px); padding: 20px;
  animation: fade .18s ease;
}
@keyframes fade { from { opacity: 0 } }
.modal-card { width: 100%; max-width: 360px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 14px; padding: 18px; display: grid; gap: 10px; }
.modal-card h3 { font-size: calc(15px * var(--type-scale)); }
.modal-card p { font-size: calc(12.5px * var(--type-scale)); color: var(--dust); }
.modal-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 4px; }
.sheet-layer { align-items: end; padding: 0; background: rgba(6,6,4,.5); backdrop-filter: none; }
.sheet-card { width: 100%; max-width: 480px; margin: 0 auto; background: var(--panel-2); border-top: 1px solid var(--line); border-radius: 16px 16px 0 0; max-height: 82dvh; display: flex; flex-direction: column; animation: rise .22s ease; }
@keyframes rise { from { transform: translateY(28px); opacity: .6 } }
.sheet-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px 8px; border-bottom: 1px solid var(--line-soft); }
.sheet-head h3 { font-size: calc(15px * var(--type-scale)); }
.sheet-body { padding: 14px 16px calc(20px + var(--safe-b)); overflow-y: auto; }

/* ---------- title ---------- */
.screen-title { justify-content: flex-end; }
.title-art { position: absolute; inset: 0; background-size: cover; background-position: center 30%; }
.title-veil { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(10,10,7,.62) 0%, rgba(10,10,7,0) 34%, rgba(10,10,7,.55) 66%, rgba(10,10,7,.96) 100%); }
.title-logo { position: relative; text-align: center; margin-top: 7dvh; padding: 0 18px; }
/* The wordmark is a stamped steel plate, so it scales as an image and can never
   overflow the way the old clamp()-sized text did. */
.title-wordmark { width: min(100%, 360px); height: auto; margin: 0 auto; filter: drop-shadow(0 8px 22px rgba(0,0,0,.8)); }
/* Both of these sit directly on the key art, where the sky is nearly the same
   value as --dust — they need their own ground to stay legible. */
.title-sub { margin-top: 10px; font-size: calc(12px * var(--type-scale)); letter-spacing: .3em; color: #E4DCC8; text-transform: none; text-shadow: 0 2px 10px rgba(0,0,0,.95), 0 0 22px rgba(0,0,0,.8); }
.press-any-key .pak-text, .press-any-key small { text-shadow: 0 2px 10px rgba(0,0,0,.95), 0 0 22px rgba(0,0,0,.85); }
.press-any-key small { color: #C9C1AE; }
.title-version { text-shadow: 0 1px 6px rgba(0,0,0,.9); }
/* Explicit rows. `press-any-key` is `display: none` once the menu opens, and
   without placement the menu slid up into the 1fr row and stretched its two
   buttons to ~280px tall each. */
.screen-title { display: grid; grid-template-rows: auto 1fr auto auto; }
.title-logo { grid-row: 1; }
.press-any-key { grid-row: 2; }
.title-menu { grid-row: 3; }
.title-version { grid-row: 4; }
.press-any-key {
  position: relative; z-index: 2; background: none; border: 0; display: grid; gap: 6px; justify-items: center;
  /* The 1fr grid row would otherwise stretch this button and fling its two
     lines to opposite ends of the screen. */
  align-content: center; align-self: center;
  padding: 20px; animation: blink 1.9s ease-in-out infinite;
}
.press-any-key .pak-text { font-family: var(--mono); font-size: calc(15px * var(--type-scale)); letter-spacing: .28em; color: var(--amber); }
.press-any-key small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
@keyframes blink { 0%,100% { opacity: 1 } 50% { opacity: .35 } }
/* align-content so the plates keep their own height even if this box is ever
   taller than its rows — a stretched grid row is what blew them up before. */
.title-menu { position: relative; z-index: 2; display: grid; align-content: end; gap: 10px; padding: 0 22px 6dvh; }
.title-version { position: relative; z-index: 2; text-align: center; padding-bottom: calc(12px + var(--safe-b)); font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); color: rgba(156,148,127,.7); letter-spacing: .1em; }

/* ---------- intro ---------- */
.screen-intro { display: grid; grid-template-rows: 42dvh 1fr auto; }
.intro-figure { position: relative; overflow: hidden; }
.intro-art { width: 100%; height: 100%; object-fit: cover; filter: sepia(.35) saturate(.75) contrast(1.05) brightness(.9); }
.intro-art.in { animation: kenburns 9s ease-out forwards; }
@keyframes kenburns { from { transform: scale(1.02) } to { transform: scale(1.12) } }
.intro-grade { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(10,8,5,.35), rgba(10,8,5,.2) 40%, rgba(15,15,11,1) 98%); }
.intro-body { display: grid; align-content: start; gap: 14px; padding: 6px 22px 0; overflow-y: auto; }
.intro-chapter { font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); letter-spacing: .22em; color: var(--amber); }
.intro-caption h2 { font-size: calc(21px * var(--type-scale)); margin: 6px 0 12px; }
.intro-lines { display: grid; gap: 7px; }
.intro-line { font-size: calc(13.5px * var(--type-scale)); color: var(--dust); line-height: 1.75; opacity: 0; animation: lineIn .55s ease forwards; animation-delay: var(--d); }
@keyframes lineIn { from { opacity: 0; transform: translateY(6px) } to { opacity: 1; transform: none } }
.intro-dots { display: flex; gap: 6px; justify-content: center; padding: 6px 0; }
.intro-dots i { width: 6px; height: 6px; border-radius: 50%; background: rgba(184,176,160,.25); }
.intro-dots i.on { background: var(--amber); }
.screen-intro > .intro-body { padding-bottom: calc(18px + var(--safe-b)); }
.intro-skip { position: absolute; top: calc(10px + var(--safe-t)); right: 12px; z-index: 3; color: var(--dust); }

/* ---------- icons ---------- */
.ic { display: inline-grid; place-items: center; width: 20px; height: 20px; flex: 0 0 auto; }
.ic svg { width: 100%; height: 100%; display: block; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------- home ----------
   The art of the zone you are standing in is the screen; everything else is a
   button floating on it. Rails sit high on the sides, play actions low in the
   middle, so nothing ever collides on a 320px-wide phone.
   No `position` here on purpose: .screen is already `absolute; inset: 0`, and
   re-declaring `relative` collapses the screen to its content height, which
   strands the footer halfway up the frame. */
/* The district plates are 9:16 like the phone, so `cover` frames them as
   painted. Only background-position animates — a transform would drift the
   whole layer off its own edges. */
.home-bg {
  position: absolute; inset: 0; background-size: cover; background-position: 50% 44%;
  filter: saturate(.88) contrast(1.02) brightness(.9);
  animation: artDrift 46s ease-in-out infinite alternate;
}
@keyframes artDrift {
  from { background-position: 40% 40%; }
  to { background-position: 60% 50%; }
}
.home-veil {
  position: absolute; inset: 0;
  background:
    radial-gradient(122% 50% at 50% 46%, rgba(10,10,7,0), rgba(10,10,7,.46) 94%),
    linear-gradient(180deg, rgba(9,9,6,.9) 0%, rgba(9,9,6,.3) 18%, rgba(9,9,6,.2) 48%, rgba(8,8,5,.88) 84%, rgba(8,8,5,.97) 100%);
}
.home-scan {
  position: absolute; inset: 0; opacity: .3; pointer-events: none;
  background-image:
    linear-gradient(rgba(197,164,59,.09) 1px, transparent 1px),
    linear-gradient(90deg, rgba(197,164,59,.09) 1px, transparent 1px);
  background-size: 46px 46px, 46px 46px;
  -webkit-mask-image: radial-gradient(78% 56% at 50% 44%, #000 0%, transparent 84%);
  mask-image: radial-gradient(78% 56% at 50% 44%, #000 0%, transparent 84%);
}

.home-hud { position: relative; z-index: 3; display: flex; align-items: center; gap: 10px; padding: 12px 12px 0; }
.hud-user {
  display: flex; align-items: center; gap: 9px; text-align: left;
  padding: 5px 13px 5px 5px; border-radius: 999px;
  border: 1px solid var(--line-soft); background: rgba(12,12,8,.7); backdrop-filter: blur(4px);
}
.hud-user img {
  width: 34px; height: 34px; border-radius: 50%; object-fit: cover; object-position: 50% 16%;
  border: 1px solid var(--line); background: rgba(0,0,0,.4);
}
.hu-text { display: grid; }
.hu-text strong { font-size: calc(12.5px * var(--type-scale)); line-height: 1.3; }
.hu-text small { font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); color: var(--muted); letter-spacing: .05em; }
.hud-pill {
  margin-left: auto; display: flex; align-items: center; gap: 6px; padding: 7px 13px; border-radius: 999px;
  border: 1px solid var(--line); background: rgba(12,12,8,.7); backdrop-filter: blur(4px);
}
.hud-pill .ic { width: 17px; height: 17px; color: var(--amber); }
.hud-pill strong { font-family: var(--mono); font-size: calc(14px * var(--type-scale)); color: var(--amber); }
.hud-pill span { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }

.home-objective {
  position: relative; z-index: 3; display: flex; align-items: center; gap: 10px; text-align: left;
  margin: 11px 12px 0; padding: 10px 12px 10px 13px; border-radius: 12px; overflow: hidden;
  border: 1px solid var(--line); backdrop-filter: blur(4px);
  background: linear-gradient(100deg, rgba(197,164,59,.2), rgba(13,13,9,.86) 56%);
}
.home-objective::before {
  content: ''; position: absolute; left: 0; top: 7px; bottom: 7px; width: 2px;
  background: var(--amber); border-radius: 0 2px 2px 0;
}
.obj-mark {
  width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center; flex: 0 0 auto;
  background: rgba(197,164,59,.16); color: var(--amber);
}
.obj-text { display: grid; gap: 1px; flex: 1; min-width: 0; }
.obj-text strong { font-size: calc(13px * var(--type-scale)); }
.obj-text strong, .obj-text small { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.obj-text small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.obj-prog { flex: 0 0 auto; font-family: var(--mono); line-height: 1; }
.obj-prog b { font-size: calc(15px * var(--type-scale)); color: var(--amber); }
.obj-prog i { font-style: normal; font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.obj-go { width: 15px; height: 15px; color: var(--muted); }
.home-objective.done {
  justify-content: center; text-align: center;
  border-color: rgba(102,117,91,.6); background: rgba(20,25,16,.82);
}
.home-objective.done .obj-text { flex: 0 0 auto; justify-items: center; }

.home-stage {
  position: relative; z-index: 3; flex: 1; min-height: 0;
  display: flex; align-items: flex-end; justify-content: center;
}
.home-rail { position: absolute; top: 16px; display: grid; gap: 8px; }
.home-rail.left { left: 10px; }
.home-rail.right { right: 10px; }
.rail-btn {
  width: 58px; display: grid; justify-items: center; gap: 4px; padding: 8px 4px 7px; border-radius: 13px;
  border: 1px solid var(--line-soft); background: rgba(13,13,9,.64); backdrop-filter: blur(4px);
  transition: transform .12s, border-color .16s, background .16s;
}
.rail-btn:active { transform: scale(.94); background: rgba(197,164,59,.14); }
.rb-face { position: relative; display: grid; place-items: center; width: 26px; height: 26px; color: var(--dust); }
.rb-face .ic { width: 22px; height: 22px; }
.rb-label { font-size: calc(11.5px * var(--type-scale)); color: var(--dust); }
.rb-dot {
  position: absolute; top: -2px; right: -5px; width: 7px; height: 7px; border-radius: 50%;
  background: var(--amber); box-shadow: 0 0 0 2px rgba(13,13,9,.9);
}
.rb-lock { position: absolute; right: -7px; bottom: -3px; width: 13px; height: 13px; color: var(--muted); }
.rail-btn.locked { opacity: .5; }

.home-actions { display: flex; align-items: flex-start; justify-content: center; gap: 14px; padding: 24px 0 6px; }
/* The faces are rotated squares: they paint ~1.41x their layout box, so the
   neighbours tile into each other and the labels need clearance underneath. */
.dia { position: relative; display: grid; justify-items: center; padding: 0; border: 0; background: none; width: 74px; margin-top: 30px; }
.dia.big { width: 92px; margin-top: 0; z-index: 2; }
.dia-face {
  width: 74px; height: 74px; border-radius: 16px; transform: rotate(45deg);
  display: grid; place-items: center;
  border: 1px solid var(--line); background: linear-gradient(150deg, rgba(48,46,35,.92), rgba(13,13,9,.94));
  box-shadow: 0 10px 24px rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,255,255,.04);
  transition: transform .14s, box-shadow .16s, border-color .16s;
}
.dia.big .dia-face {
  width: 92px; height: 92px; border-radius: 19px; border-color: rgba(224,192,105,.7);
  background: linear-gradient(150deg, rgba(197,164,59,.44), rgba(32,29,17,.95));
  box-shadow: 0 14px 30px rgba(0,0,0,.6), 0 0 28px rgba(197,164,59,.2), inset 0 0 0 1px rgba(255,244,205,.14);
}
.dia:active .dia-face { transform: rotate(45deg) scale(.93); }
.dia-in { transform: rotate(-45deg); display: grid; place-items: center; color: var(--dust); }
.dia-in .ic { width: 26px; height: 26px; }
.dia.big .dia-in { color: #f4e6b4; }
.dia.big .dia-in .ic { width: 34px; height: 34px; }
.dia-label {
  margin-top: 20px; font-size: calc(11.5px * var(--type-scale)); font-weight: 700;
  white-space: nowrap; text-shadow: 0 2px 8px rgba(0,0,0,.95);
}
.dia.big .dia-label { margin-top: 26px; font-size: calc(14px * var(--type-scale)); color: #f5e7b6; }
.dia-note { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); white-space: nowrap; text-shadow: 0 2px 8px rgba(0,0,0,.95); }

.home-foot { position: relative; z-index: 3; display: grid; gap: 8px; padding: 6px 12px calc(14px + var(--safe-b)); }
.home-ticker {
  display: flex; align-items: center; gap: 9px; padding: 7px 11px; border-radius: 10px;
  border: 1px solid var(--line-soft); background: rgba(10,10,7,.74); backdrop-filter: blur(4px);
}
.home-ticker .code { flex: 0 0 auto; }
.home-ticker p {
  font-size: calc(11.5px * var(--type-scale)); color: var(--dust); overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.home-meter { display: grid; grid-template-columns: auto auto; gap: 4px 10px; align-items: center; }
.home-meter span { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.home-meter strong { justify-self: end; font-family: var(--mono); font-size: calc(12px * var(--type-scale)); color: var(--amber); }
.home-meter .bar { grid-column: 1 / -1; }

/* ---------- meta screens ---------- */
.meta-top, .map-top { position: relative; z-index: 3; display: flex; align-items: center; gap: 12px; padding: 14px 16px 10px; border-bottom: 1px solid var(--line-soft); flex: 0 0 auto; }
.meta-top h2, .map-top h2 { font-size: calc(17px * var(--type-scale)); }
.map-top.ontop { border-bottom: 0; }
.map-total { margin-left: auto; text-align: right; }
.map-total strong { font-size: calc(17px * var(--type-scale)); color: var(--amber); }
.map-total span { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.meta-body { flex: 1; overflow-y: auto; padding: 4px 16px calc(24px + var(--safe-b)); }

.shop-list { display: grid; gap: 8px; }
.shop-card { display: grid; grid-template-columns: 40px 1fr auto; gap: 10px; align-items: center; padding: 10px; border-radius: 10px; border: 1px solid var(--line-soft); background: rgba(28,27,20,.7); }
.shop-card.equipped { border-color: var(--amber); }
.swatch { width: 40px; height: 40px; border-radius: 8px; background: linear-gradient(135deg, #4a4536, #2a2820); border: 1px solid var(--line-soft); }
.sw-pack-civil { background: linear-gradient(135deg, #35506b, #1d2b3a); }
.sw-pack-hazard { background: linear-gradient(135deg, #b89129, #6a5215); }
.sw-pack-scorched { background: linear-gradient(135deg, #2b2b2b, #101010); }
.sw-hud-amber { background: linear-gradient(135deg, #c5a43b, #6d5a1c); }
.sw-hud-teal { background: linear-gradient(135deg, #4f7472, #263a39); }
.shop-info strong { display: block; font-size: calc(13px * var(--type-scale)); }
.shop-info small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }

.mission-list { display: grid; gap: 8px; }
.mission-card { display: grid; grid-template-columns: 1fr auto; gap: 10px; align-items: center; padding: 11px; border-radius: 10px; border: 1px solid var(--line-soft); background: rgba(28,27,20,.7); }
.mission-card.ready { border-color: var(--amber); }
.mission-card.claimed { opacity: .55; }
.mission-info strong { display: block; font-size: calc(12.5px * var(--type-scale)); margin-bottom: 6px; }
.mission-info small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.mission-info .bar { margin-bottom: 4px; }

.codex-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.codex-card { display: grid; gap: 4px; justify-items: center; padding: 10px 6px; border-radius: 10px; border: 1px solid var(--line-soft); background: rgba(28,27,20,.7); min-height: 104px; }
.codex-card img { height: 44px; width: auto; object-fit: contain; }
.codex-card strong { font-size: calc(11.5px * var(--type-scale)); text-align: center; line-height: 1.25; }
.codex-card.unknown { opacity: .48; }
.codex-card .q { font-size: calc(26px * var(--type-scale)); color: var(--muted); height: 44px; display: grid; place-items: center; }
.codex-detail { display: grid; gap: 12px; }
.codex-hero { max-height: 170px; width: auto; margin: 0 auto; object-fit: contain; }
.codex-meta { display: grid; gap: 6px; }
.codex-meta > div { display: flex; justify-content: space-between; gap: 12px; font-size: calc(12px * var(--type-scale)); }
.codex-meta span { color: var(--muted); }
.codex-memo { margin: 0; padding: 10px 12px; border-left: 2px solid var(--amber); background: rgba(197,164,59,.08); font-size: calc(12px * var(--type-scale)); color: var(--dust); font-style: italic; }
.codex-shape { display: grid; place-items: center; padding: 8px; }

.profile-badge { display: grid; grid-template-columns: 56px 1fr; gap: 12px; align-items: center; padding: 12px; border-radius: 12px; border: 1px solid var(--line-soft); background: rgba(28,27,20,.7); }
.profile-badge img { width: 56px; height: 56px; border-radius: 10px; object-fit: cover; }
.profile-badge small { color: var(--muted); font-size: calc(11.5px * var(--type-scale)); }
.profile-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 14px 0; }
.profile-stats > div { display: flex; justify-content: space-between; padding: 9px 11px; border-radius: 8px; background: rgba(255,255,255,.04); font-size: calc(12px * var(--type-scale)); }
.profile-stats span { color: var(--muted); }
.profile-zones { display: grid; gap: 8px; margin-bottom: 18px; }
.zone-row { display: grid; grid-template-columns: 1fr 70px auto; gap: 8px; align-items: center; font-size: calc(11.5px * var(--type-scale)); }
.settings { display: grid; gap: 4px; }
.setting-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 2px; border-bottom: 1px solid var(--line-soft); font-size: calc(13px * var(--type-scale)); }

/* ---------- world map ---------- */
.world-map { position: relative; flex: 1; overflow: hidden; margin: 0 14px; border-radius: 14px; border: 1px solid var(--line-soft); }
.world-bg { position: absolute; inset: 0; background-size: cover; background-position: center; filter: saturate(.6) contrast(1.05); }
.world-veil { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(12,12,8,.55), rgba(12,12,8,.75)); }
.world-links { position: absolute; inset: 0; width: 100%; height: 100%; }
.world-links .link { stroke: rgba(184,176,160,.2); stroke-width: .5; stroke-dasharray: 2 2; }
.world-links .link.on { stroke: rgba(197,164,59,.5); stroke-dasharray: none; }
.zone-node {
  position: absolute; transform: translate(-50%, -50%); display: grid; gap: 1px; justify-items: center;
  min-width: 92px; padding: 8px 10px; border-radius: 10px;
  border: 1px solid var(--line); background: rgba(18,18,12,.88); text-align: center;
}
.zone-node.locked { opacity: .5; border-color: var(--line-soft); }
.zone-node.cleared { border-color: var(--green); box-shadow: 0 0 0 2px rgba(102,117,91,.22); }
.node-index { font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); color: var(--amber); }
.node-name { font-size: calc(12px * var(--type-scale)); font-weight: 700; }
.node-prog { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); font-family: var(--mono); }
.node-sits { display: flex; gap: 3px; margin-top: 2px; }
.sit-dot { width: 5px; height: 5px; border-radius: 50%; background: rgba(79,116,114,.85); }
.world-legend { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 14px; }

/* ---------- zone map ----------
   One route through the district, drawn bottom-up over the zone art. The art
   stays put while the route scrolls, so the district reads as a place you are
   looking at rather than a list you are paging through. .screen already sets
   `position: absolute; inset: 0` — see the note on the home block. */
/* Same plate as home, held further back: the route and its labels have to stay
   readable on top of it. */
.zone-bg {
  position: absolute; inset: 0; background-size: cover; background-position: 50% 46%;
  filter: saturate(.62) contrast(1.04) brightness(.62);
}
.zone-veil {
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 58% at 50% 44%, rgba(10,10,7,.1), rgba(8,8,5,.7) 90%),
    linear-gradient(180deg, rgba(8,8,5,.92) 0%, rgba(8,8,5,.4) 16%, rgba(8,8,5,.42) 58%, rgba(8,8,5,.95) 100%);
}
.screen-zone .map-top { z-index: 4; border-bottom: 0; }
.zone-brief { position: relative; z-index: 4; display: grid; gap: 6px; padding: 0 14px 8px; }
.zone-flavour { font-size: calc(11.5px * var(--type-scale)); color: var(--dust); text-shadow: 0 2px 8px rgba(0,0,0,.9); }
.zone-chips { display: flex; gap: 5px; overflow-x: auto; padding-bottom: 2px; scrollbar-width: none; }
.zone-chips::-webkit-scrollbar { display: none; }
.zone-chips .chip { flex: 0 0 auto; background: rgba(10,10,7,.7); backdrop-filter: blur(3px); }

.route-scroll { position: relative; z-index: 2; flex: 1; overflow-y: auto; overscroll-behavior: contain; }
.route { position: relative; width: 100%; }
.route::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(184,176,160,.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(184,176,160,.055) 1px, transparent 1px);
  background-size: 42px 42px, 42px 42px;
}
/* The viewBox is stretched to the frame width, so every stroke is pinned to
   pixels and the glow is built from stacked strokes rather than a blur — a
   filter would smear anisotropically under that scale. */
.route-lines { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.route-lines path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.route-lines .halo.on { stroke: rgba(197,164,59,.12); stroke-width: 12; }
.route-lines .mid.on { stroke: rgba(214,178,74,.26); stroke-width: 5; }
.route-lines .core.on { stroke: #efd68a; stroke-width: 1.7; }
.route-lines .halo.off { stroke: rgba(184,176,160,.05); stroke-width: 9; }
.route-lines .mid.off { stroke: transparent; stroke-width: 0; }
.route-lines .core.off { stroke: rgba(184,176,160,.36); stroke-width: 1.2; stroke-dasharray: 3 6; }

.rnode {
  position: absolute; width: 44px; height: 44px; padding: 0; border: 0; background: none;
  transform: translate(-50%, 50%);
}
.rn-ring {
  position: relative; display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%;
  border: 1px solid rgba(184,176,160,.4); background: rgba(9,9,6,.88);
  transition: box-shadow .18s, border-color .18s, transform .14s;
}
.rn-ring b { font-family: var(--mono); font-size: calc(12.5px * var(--type-scale)); color: var(--dust); }
.rnode:active .rn-ring { transform: scale(.92); }
.rnode.optional .rn-ring { border-style: dashed; }
.rnode.cleared .rn-ring {
  border-color: rgba(132,153,116,.9); background: rgba(18,24,15,.9);
  box-shadow: 0 0 0 4px rgba(102,117,91,.12), 0 0 16px rgba(102,117,91,.3);
}
.rnode.cleared .rn-ring b { color: #cfe0c0; }
.rnode.t-elite .rn-ring { border-color: rgba(214,178,74,.55); }
.rnode.t-boss .rn-ring, .rnode.t-midboss .rn-ring { border-color: rgba(190,74,74,.85); background: rgba(30,13,12,.9); }
.rnode.t-boss .rn-ring b { color: #f0b9b9; }
.rnode.locked { opacity: .46; }
.rnode.sel { z-index: 3; }
.rnode.sel .rn-ring {
  border-color: var(--amber);
  box-shadow: 0 0 0 5px rgba(197,164,59,.15), 0 0 28px rgba(197,164,59,.5);
}
.rnode.sel:not(.cleared) .rn-ring { animation: nodePulse 2.4s ease-in-out infinite; }
@keyframes nodePulse {
  0%, 100% { box-shadow: 0 0 0 5px rgba(197,164,59,.15), 0 0 24px rgba(197,164,59,.4); }
  50% { box-shadow: 0 0 0 8px rgba(197,164,59,.07), 0 0 34px rgba(197,164,59,.66); }
}
.rn-label {
  position: absolute; left: 54px; top: 50%; transform: translateY(-50%); width: 114px;
  display: grid; gap: 1px; text-align: left; padding: 5px 8px; border-radius: 7px;
  border: 1px solid var(--line-soft); background: rgba(9,9,6,.82); backdrop-filter: blur(3px);
}
.rnode.flip .rn-label { left: auto; right: 54px; text-align: right; }
.rn-label::before {
  content: ''; position: absolute; right: 100%; top: 50%; width: 10px; height: 1px;
  background: rgba(184,176,160,.35);
}
.rnode.flip .rn-label::before { right: auto; left: 100%; }
.rn-label strong { font-size: calc(11.5px * var(--type-scale)); }
.rn-label small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.rnode.sel .rn-label { border-color: var(--amber); background: rgba(24,20,9,.9); }
.rnode.cleared .rn-label strong { color: var(--dust); }

.route-marker { position: absolute; transform: translateX(-50%); display: grid; justify-items: center; gap: 1px; width: 120px; text-align: center; }
.route-marker.start { bottom: 12px; }
.route-marker.end { top: 12px; }
.route-marker small { font-size: calc(11.5px * var(--type-scale)); color: var(--dust); text-shadow: 0 2px 8px rgba(0,0,0,.9); }

/* Sticky rather than absolute: the fades ride the scrollport, so the route
   dissolves into the header and the stop card instead of being cut off. */
.route-fade { position: sticky; z-index: 5; pointer-events: none; }
.route-fade.top { top: 0; height: 30px; margin-bottom: -30px; background: linear-gradient(180deg, rgba(8,8,5,.8), rgba(8,8,5,0)); }
.route-fade.bottom { bottom: 0; height: 92px; margin-top: -92px; background: linear-gradient(180deg, rgba(8,8,5,0), rgba(8,8,5,.9)); }
.route-card {
  position: relative; z-index: 4; display: grid; gap: 7px; flex: 0 0 auto;
  margin: 0 12px calc(12px + var(--safe-b)); padding: 12px; border-radius: 13px;
  border: 1px solid var(--line); background: rgba(16,15,10,.93); backdrop-filter: blur(6px);
  box-shadow: 0 -6px 26px rgba(0,0,0,.5);
}
.route-card.t-boss, .route-card.t-midboss { border-color: rgba(142,45,45,.7); }
.route-card.locked { opacity: .82; }
.rc-head { display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center; }
.rc-num { font-family: var(--mono); font-size: calc(21px * var(--type-scale)); color: var(--amber); line-height: 1; }
.rc-title h3 { font-size: calc(15px * var(--type-scale)); margin-top: 1px; }
.rc-state b { font-size: calc(11.5px * var(--type-scale)); font-weight: 600; padding: 3px 7px; border-radius: 999px; }
.rc-state .ok { background: rgba(102,117,91,.3); color: #cfe0c0; }
.rc-state .open { background: rgba(197,164,59,.2); color: #eed99b; }
.rc-state .partial { background: rgba(79,116,114,.25); color: #a9cfcb; }
.rc-state .lock { background: rgba(255,255,255,.06); color: var(--muted); }
.rc-note { font-size: calc(11.5px * var(--type-scale)); color: rgba(169,207,203,.9); }
.rc-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.route-card .btn { margin-top: 2px; }

/* ---------- brief ---------- */
/* No `position` here: .screen is already `absolute; inset: 0`, and re-declaring
   `relative` collapses the screen to its content height — it stranded the 출동
   button 300px above the bottom of the frame. Same fix as home and zone. */
.brief-bg { position: absolute; inset: 0; background-size: cover; background-position: center; }
.brief-veil { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(10,10,7,.72), rgba(10,10,7,.96)); }
.brief-body { position: relative; flex: 1; overflow-y: auto; padding: 6px 16px 12px; display: grid; gap: 12px; align-content: start; }
.brief-card { padding: 12px; border-radius: 10px; border: 1px solid var(--line); background: rgba(28,27,20,.8); }
.brief-card h3 { font-size: calc(16px * var(--type-scale)); margin: 4px 0; }
.brief-card .sit-note { font-size: calc(12px * var(--type-scale)); color: rgba(169,207,203,.9); }
.brief-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.brief-grid > div { display: grid; gap: 2px; padding: 9px 11px; border-radius: 8px; background: rgba(255,255,255,.04); }
.brief-grid span { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.brief-grid strong { font-size: calc(12.5px * var(--type-scale)); }
.enemy-strip { display: flex; gap: 6px; margin-top: 6px; overflow-x: auto; padding-bottom: 4px; }
.enemy-chip { position: relative; flex: 0 0 auto; width: 52px; height: 62px; border-radius: 8px; border: 1px solid var(--line-soft); background: rgba(255,255,255,.04); overflow: hidden; display: grid; place-items: end center; }
.enemy-chip img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; object-position: bottom; }
.enemy-chip span { position: relative; font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); background: rgba(0,0,0,.6); width: 100%; text-align: center; }

/* ---------- prepare ---------- */
.progress-strip { flex: 0 0 auto; padding: 8px 14px 6px; background: rgba(12,12,8,.9); border-bottom: 1px solid var(--line-soft); }
.ps-labels { display: flex; gap: 8px; justify-content: space-between; font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); color: var(--dust); letter-spacing: .04em; }
.ps-labels .ps-enc { color: var(--amber); }
.ps-labels .ps-pct { color: var(--muted); }
.ps-bar { height: 4px; margin-top: 5px; border-radius: 2px; background: rgba(255,255,255,.08); overflow: hidden; }
.ps-bar > b { display: block; height: 100%; background: var(--amber); transition: width .35s; }
.status-row { flex: 0 0 auto; display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line-soft); border-bottom: 1px solid var(--line-soft); }
/* Four 1fr tracks are ~8px too narrow for "생존력 100 /100" at 320px, and the
   overflow scales with --text-scale, so a width-only media query can't cover it.
   Letting whole tokens wrap to a second line gives the layout a legal escape
   instead of breaking a Korean label mid-word. */
.status-row .st { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 4px; justify-content: center; min-width: 0; padding: 7px 4px; background: rgba(16,16,11,.95); }
.status-row .st span, .status-row .st i { white-space: nowrap; }
.status-row .st span { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.status-row .st strong { font-size: calc(14px * var(--type-scale)); }
.status-row .st i { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); font-style: normal; }
.status-row .hp strong { color: #cfe0c0; }
.status-row .scrap strong { color: var(--amber); }
.status-row .noise.tier-1 strong { color: #e5b25a; }
.status-row .noise.tier-2 strong { color: #f08a8a; }
.status-row .bleed.on strong { color: #f08a8a; }

.main-tabs { flex: 0 0 auto; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--line-soft); }
.main-tab { display: grid; gap: 0; justify-items: center; padding: 8px 4px 7px; background: rgba(16,16,11,.95); border: 0; border-bottom: 2px solid transparent; }
.main-tab .tab-code { font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); color: var(--muted); letter-spacing: .1em; }
.main-tab strong { font-size: calc(12.5px * var(--type-scale)); }
.main-tab .tab-count { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.main-tab.on { background: rgba(197,164,59,.12); border-bottom-color: var(--amber); }
.main-tab.on .tab-code, .main-tab.on .tab-count { color: var(--amber); }
.panel-host { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.panel { padding: 12px 14px calc(20px + var(--safe-b)); display: grid; gap: 10px; align-content: start; }
.panel-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; }
.panel-head h3 { font-size: calc(16px * var(--type-scale)); }
.cell-count { font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); color: var(--amber); }

/* A salvage */
.offer-list { display: grid; gap: 8px; }
.offer-card { display: grid; grid-template-columns: 62px 1fr; gap: 10px; padding: 10px; border-radius: 10px; border: 1px solid var(--line-soft); background: rgba(28,27,20,.72); }
.offer-card.taken { opacity: .42; }
.offer-card.poor { border-color: rgba(142,45,45,.35); }
.offer-visual { display: grid; gap: 5px; justify-items: center; align-content: start; }
.offer-visual img { width: 58px; height: 50px; object-fit: contain; }
.offer-info { display: grid; gap: 2px; align-content: start; }
.offer-title { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.offer-title strong { font-size: calc(13.5px * var(--type-scale)); }
.offer-title .price { font-family: var(--mono); font-size: calc(14px * var(--type-scale)); color: var(--amber); }
.offer-role { font-size: calc(11.5px * var(--type-scale)); color: var(--dust); }
.offer-shape { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.offer-actions { grid-column: 1 / -1; display: grid; grid-template-columns: 1fr auto; gap: 6px; margin-top: 2px; }
.item-detail { display: grid; gap: 12px; }
.detail-art { max-height: 160px; width: auto; margin: 0 auto; object-fit: contain; }
.detail-rows { display: grid; gap: 5px; }
.detail-rows > div { display: flex; justify-content: space-between; font-size: calc(12px * var(--type-scale)); }
.detail-rows span { color: var(--muted); }
.detail-shape { display: grid; place-items: center; }

/* B pack */
.sub-tabs { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 4px; }
.sub-tab { display: flex; align-items: baseline; justify-content: center; gap: 5px; padding: 8px 4px; border-radius: 8px; border: 1px solid var(--line-soft); background: rgba(255,255,255,.03); }
.sub-tab strong { font-size: calc(12px * var(--type-scale)); }
.sub-tab small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.sub-tab.on { background: rgba(197,164,59,.16); border-color: var(--amber); }
.grid-view { display: grid; gap: 10px; }
.inspector { display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 8px 10px; border-radius: 10px; border: 1px solid var(--line-soft); background: rgba(255,255,255,.04); }
.inspector .hint { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.item-thumb { width: 40px; height: 40px; flex: 0 0 auto; display: grid; place-items: center; }
.item-thumb img { max-height: 40px; object-fit: contain; }
.insp-info strong { display: block; font-size: calc(13px * var(--type-scale)); }
.insp-info small { display: block; font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.insp-info .ammo { color: var(--amber); }
.zone-callouts { display: flex; gap: 6px; justify-content: space-between; }
.zc { flex: 1; text-align: center; font-size: calc(11.5px * var(--type-scale)); padding: 3px 4px; border-radius: 6px; color: var(--dust); }
.zc.belt { background: rgba(197,164,59,.16); }
.zc.pocket { background: rgba(79,116,114,.18); }
.zc.pack { background: rgba(102,117,91,.16); }

.board-wrap { position: relative; }
.pack-board {
  position: relative; display: grid; grid-template-columns: repeat(8, 1fr); grid-template-rows: repeat(6, 1fr);
  gap: 2px; aspect-ratio: 8 / 6; width: 100%; padding: 3px; border-radius: 10px;
  /* Real canvas under the grid — the board is meant to read as a fabric
     organiser, not a flat panel. The gradient stays as the tint the skins swap. */
  background-color: #3a3629;
  background-image: url('./assets/art/ui/canvas.webp'), linear-gradient(160deg, #4a4536, #2c2a20);
  background-size: 180px auto, cover;
  background-blend-mode: multiply, normal;
  border: 1px solid var(--line);
  box-shadow: inset 0 0 24px rgba(0,0,0,.55);
}
/* Skins re-tint the canvas rather than replacing it, so the fabric survives the
   swap — a cosmetic must never change how the board reads (GDD 12.7). */
body[data-pack-skin="pack-civil"] .pack-board { background-color: #294056; background-image: url('./assets/art/ui/canvas.webp'), linear-gradient(160deg, #35506b, #1d2b3a); }
body[data-pack-skin="pack-hazard"] .pack-board { background-color: #6d5518; background-image: url('./assets/art/ui/canvas.webp'), linear-gradient(160deg, #8a6d1f, #3b2f0f); }
body[data-pack-skin="pack-scorched"] .pack-board { background-color: #232320; background-image: url('./assets/art/ui/canvas.webp'), linear-gradient(160deg, #2f2f2c, #131312); }
.pack-board .cell { border: 0; border-radius: 4px; background: rgba(10,10,7,.42); box-shadow: inset 0 0 0 1px rgba(255,255,255,.05); transition: background .12s, box-shadow .12s; }
.pack-board .cell.blocked { background: repeating-linear-gradient(45deg, rgba(0,0,0,.5) 0 4px, rgba(0,0,0,.28) 4px 8px); box-shadow: none; }
.pack-board .cell.a-BELT { background: rgba(197,164,59,.16); }
.pack-board .cell.a-POCKET_L, .pack-board .cell.a-POCKET_R { background: rgba(79,116,114,.2); }
.pack-board .cell.legal { background: rgba(102,117,91,.55); box-shadow: inset 0 0 0 1px rgba(160,200,140,.6); }
.pack-board .cell.bad { animation: cellbad .6s ease; }
@keyframes cellbad { 0%,100% { background: rgba(142,45,45,.2) } 30% { background: rgba(200,60,60,.75) } }
.item-layer { position: absolute; inset: 3px; pointer-events: none; }
.pack-item { position: absolute; padding: 0; border: 0; background: none; pointer-events: auto; touch-action: none; -webkit-user-select: none; user-select: none; }
.pi-cells { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(var(--w), 1fr); grid-template-rows: repeat(var(--h), 1fr); gap: 2px; }
.pi-cells i { border-radius: 4px; }
.pi-cells i.on { background: rgba(120,110,86,.92); box-shadow: inset 0 0 0 1px rgba(240,224,180,.28); }
.pack-item.selected .pi-cells i.on { background: rgba(160,136,66,.95); box-shadow: inset 0 0 0 1px var(--amber), 0 0 8px rgba(197,164,59,.5); }
/* The artwork turns with the footprint. On a quarter turn the picture needs the
   transposed box — a knife lying in a 2x1 slot has to be drawn into a 1x2 area
   and then rotated — so the box is expressed against the opposite axis using
   the item's own --w/--h cell counts. 84% of the parent's height, written as a
   width, is `84% * h / w`. */
.pi-art {
  position: absolute; left: 50%; top: 50%; width: 84%; height: 84%;
  object-fit: contain; filter: drop-shadow(0 1px 2px rgba(0,0,0,.7));
  transform: translate(-50%, -50%);
  transition: transform .12s ease;
}
[data-rot="1"] > .pi-art, [data-rot="3"] > .pi-art {
  width: calc(84% * var(--h) / var(--w));
  height: calc(84% * var(--w) / var(--h));
}
[data-rot="1"] > .pi-art { transform: translate(-50%, -50%) rotate(90deg); }
[data-rot="2"] > .pi-art { transform: translate(-50%, -50%) rotate(180deg); }
[data-rot="3"] > .pi-art { transform: translate(-50%, -50%) rotate(270deg); }
body.reduce-motion .pi-art { transition: none; }
.pi-badge { position: absolute; right: -2px; bottom: -2px; min-width: 15px; padding: 0 3px; border-radius: 999px; background: rgba(10,10,7,.92); border: 1px solid var(--line); font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); color: var(--amber); }
.pi-badge.empty { border-color: var(--bleed); color: #f08a8a; }
.pack-actions { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.pack-actions .btn { min-height: 40px; padding: 6px 4px; font-size: calc(11.5px * var(--type-scale)); flex-direction: row; gap: 4px; }

/* ---------- floor tray + drag placement ---------- */
/* The tray sits under the board so a pick-up-and-place is one continuous drag.
   It scrolls sideways: a haul of ten items must never push the board off
   screen, because the board is the thing being aimed at. */
.floor-tray { display: grid; gap: 7px; padding: 9px 9px 8px; border-radius: 10px; border: 1px solid var(--line-soft); background: rgba(16,16,11,.5); }
.tray-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.tray-head .code { margin-right: 6px; }
.tray-head strong { font-size: calc(12px * var(--type-scale)); }
.tray-head .text-btn { padding: 2px 4px; font-size: calc(11.5px * var(--type-scale)); }
.tray-empty { padding: 12px 6px; font-size: calc(11.5px * var(--type-scale)); }
.tray-note { font-size: calc(11.5px * var(--type-scale)); }
.tray-strip {
  display: flex; gap: 7px; overflow-x: auto; overflow-y: hidden;
  padding-bottom: 3px; scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch; scrollbar-width: thin;
}
.tray-card {
  position: relative; flex: 0 0 auto; width: 74px; scroll-snap-align: start;
  display: grid; gap: 2px; justify-items: center; padding: 6px 4px 5px;
  border-radius: 9px; border: 1px solid var(--line-soft); background: rgba(28,27,20,.82);
  /* The card is a drag handle: the browser must not claim the gesture for a
     scroll, or the first pixel of every placement is lost to the tray. */
  touch-action: none; -webkit-user-select: none; user-select: none;
}
.tray-card.selected { border-color: var(--amber); background: rgba(197,164,59,.14); }
.tray-card img { height: 34px; width: auto; object-fit: contain; pointer-events: none; }
/* Footprint rides in the corner rather than on its own row — the tray has to
   stay short enough that the board never leaves the screen behind it. */
.tray-card .shape-block { position: absolute; left: 4px; top: 4px; pointer-events: none; opacity: .9; }
.tray-card strong {
  max-width: 100%; font-size: calc(11.5px * var(--type-scale)); line-height: 1.2; text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* The item rides above the fingertip, so it is the one thing on screen that is
   never occluded by the hand placing it. */
.drag-ghost {
  position: fixed; left: 0; top: 0; z-index: 120; pointer-events: none;
  transform: translate(-999px, -999px); will-change: transform;
  filter: drop-shadow(0 8px 14px rgba(0,0,0,.75));
}
.drag-ghost .pi-cells i.on { background: rgba(168,143,70,.95); box-shadow: inset 0 0 0 1px rgba(240,224,180,.5); }
.drag-ghost.snapped { transition: transform .07s linear; }
.drag-ghost.snapped .pi-cells i.on { background: rgba(120,150,96,.96); box-shadow: inset 0 0 0 1px rgba(190,230,170,.9), 0 0 10px rgba(140,190,120,.55); }
.drag-hint {
  position: fixed; z-index: 121; left: 50%; bottom: calc(14px + var(--safe-b)); transform: translateX(-50%);
  padding: 6px 12px; border-radius: 999px; pointer-events: none; white-space: nowrap;
  background: rgba(12,12,8,.9); border: 1px solid var(--line); color: var(--dust);
  font-size: calc(11.5px * var(--type-scale)); box-shadow: 0 4px 16px rgba(0,0,0,.55);
}
.pack-board .cell.drop-ok { background: rgba(102,117,91,.72); box-shadow: inset 0 0 0 1px rgba(180,220,160,.85); }
.pack-board .cell.drop-bad { background: rgba(142,45,45,.55); box-shadow: inset 0 0 0 1px rgba(220,120,120,.7); }
.pack-item.lifted, .tray-card.lifted { opacity: .18; }
body.dragging-item { -webkit-user-select: none; user-select: none; }

.craft-view { display: grid; gap: 10px; }
.craft-card { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: center; padding: 11px; border-radius: 10px; border: 1px solid var(--line-soft); background: rgba(28,27,20,.72); opacity: .68; }
.craft-card.ready { opacity: 1; border-color: var(--amber); }
.craft-mats { display: grid; gap: 6px; }
.craft-mat { display: grid; grid-template-columns: 34px 1fr; gap: 6px; align-items: center; }
.craft-mat img { height: 30px; object-fit: contain; }
.craft-mat small { font-size: calc(11.5px * var(--type-scale)); color: var(--dust); }
.craft-arrow { color: var(--amber); font-size: calc(18px * var(--type-scale)); }
.craft-result { display: grid; gap: 3px; justify-items: center; }
.craft-result img { height: 46px; object-fit: contain; }
.craft-result strong { font-size: calc(12px * var(--type-scale)); }
.craft-result small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); text-align: center; }
.craft-actions { grid-column: 1 / -1; display: grid; gap: 5px; }
.craft-why { font-size: calc(11.5px * var(--type-scale)); color: #d8a05a; }

/* C threat */
.rating { padding: 4px 10px; border-radius: 999px; font-size: calc(12px * var(--type-scale)); font-weight: 700; }
.rating.r-ADVANTAGE { background: rgba(102,117,91,.35); color: #cfe0c0; }
.rating.r-CLOSE { background: rgba(197,164,59,.25); color: #eed99b; }
.rating.r-DANGER, .rating.r-NO_ATTACK { background: rgba(142,45,45,.32); color: #f2b6b6; }
.faceoff { display: grid; grid-template-columns: 1fr 44px 1fr; align-items: end; gap: 6px; padding: 6px 0; }
.fo-side { display: grid; justify-items: center; gap: 4px; }
.fo-side .cutout { height: 128px; width: auto; object-fit: contain; filter: drop-shadow(0 6px 12px rgba(0,0,0,.6)); }
.fo-side.foe .cutout { transform: scaleX(1); }
.fo-side span { font-size: calc(11.5px * var(--type-scale)); color: var(--dust); text-align: center; }
.fo-vs { display: grid; justify-items: center; gap: 4px; padding-bottom: 22px; }
.fo-vs i { width: 1px; height: 14px; background: var(--line); }
.fo-vs b { font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); color: var(--amber); }
.enemy-desc { font-size: calc(12px * var(--type-scale)); color: var(--dust); }
.enemy-stats { display: grid; grid-template-columns: repeat(5, 1fr); gap: 1px; background: var(--line-soft); border-radius: 8px; overflow: hidden; }
.enemy-stats > div { display: grid; gap: 1px; justify-items: center; padding: 7px 2px; background: rgba(20,20,14,.9); }
.enemy-stats dt { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.enemy-stats dd { font-size: calc(12.5px * var(--type-scale)); font-weight: 700; }
.intel { display: flex; gap: 8px; align-items: baseline; padding: 9px 11px; border-radius: 8px; background: rgba(79,116,114,.16); }
.intel span { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); flex: 0 0 auto; }
.intel strong { font-size: calc(12px * var(--type-scale)); color: #a9cfcb; }
.forecast { padding: 11px; border-radius: 10px; border: 1px solid var(--line-soft); background: rgba(28,27,20,.75); display: grid; gap: 9px; }
.forecast.r-ADVANTAGE { border-color: rgba(102,117,91,.5); }
.forecast.r-CLOSE { border-color: rgba(197,164,59,.5); }
.forecast.r-DANGER { border-color: rgba(142,45,45,.55); }
.fc-head { display: grid; gap: 2px; }
.fc-head strong { font-size: calc(15px * var(--type-scale)); }
.fc-head small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.fc-rows { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.fc-rows > div { display: grid; gap: 1px; padding: 7px 9px; border-radius: 7px; background: rgba(255,255,255,.04); }
.fc-rows span { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.fc-rows strong { font-size: calc(11.5px * var(--type-scale)); }
.fc-list { display: grid; gap: 4px; }
.fc-list li { font-size: calc(11.5px * var(--type-scale)); padding-left: 14px; position: relative; }
.fc-list li::before { position: absolute; left: 0; }
.fc-list.good li { color: #cfe0c0; }
.fc-list.good li::before { content: "+"; color: var(--green); }
.fc-list.bad li { color: #eab8b8; }
.fc-list.bad li::before { content: "!"; color: var(--bleed); }
.decide { display: grid; gap: 8px; margin-top: 4px; }

/* ---------- combat ---------- */
.combat-stage { position: relative; flex: 0 0 auto; height: 40dvh; min-height: 240px; background-size: cover; background-position: center; overflow: hidden; }
.combat-veil { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(10,10,7,.55), rgba(10,10,7,.9)); }
.combat-head { position: relative; display: flex; justify-content: space-between; align-items: center; padding: 8px 14px; }
.combat-clock { font-family: var(--mono); font-size: calc(15px * var(--type-scale)); color: var(--amber); }
/* `min-height: 0` on every rung of this ladder is load-bearing. Without it the
   1fr art track refuses to shrink below the illustration's own height, the
   column grows past the stage, and `.combat-stage`'s overflow:hidden silently
   eats the health bar and the chips off the bottom edge. */
.combatants {
  position: relative; display: grid;
  grid-template-columns: 1fr 1fr; grid-template-rows: minmax(0, 1fr) auto;
  row-gap: 6px; column-gap: 8px; padding: 0 12px 10px;
  height: calc(100% - 40px); min-height: 0;
}
/* Both sides share the two rows rather than each owning a private grid: the
   player carries four status chips and the threat one, and with separate grids
   that difference pushed the two illustrations onto different baselines. */
.cbt { display: contents; }
.cbt.you > * { grid-column: 1; }
.cbt.foe > * { grid-column: 2; }
.cbt-art { grid-row: 1; }
.cbt-meta { grid-row: 2; }
.cbt-art { position: relative; min-height: 0; display: flex; align-items: flex-end; justify-content: center; transform-origin: 50% 100%; }
.cbt .cutout { height: 100%; width: 100%; object-fit: contain; object-position: bottom; filter: drop-shadow(0 6px 12px rgba(0,0,0,.65)); }

/* being hit: recoil away from the blow, flash red */
.cbt-art.hurt { animation: recoil .38s cubic-bezier(.36,.07,.19,.97) both; }
.cbt-art.hurt .cutout { animation: hitflash .38s ease-out both; }
/* reduce-motion path: a steady red rim for as long as the class is on, so the
   struck side is still identifiable without a jolt or a flash */
.cbt-art.hurt-still .cutout { filter: drop-shadow(0 6px 12px rgba(0,0,0,.65)) drop-shadow(0 0 7px rgba(255,96,96,.95)); }
.cbt.you .cbt-art.hurt { --recoil: -1; }
.cbt.foe .cbt-art.hurt { --recoil: 1; }
@keyframes recoil {
  0%   { transform: translateX(0) }
  12%  { transform: translateX(calc(var(--recoil, 1) * 9px)) rotate(calc(var(--recoil, 1) * 2.5deg)) }
  30%  { transform: translateX(calc(var(--recoil, 1) * -5px)) rotate(calc(var(--recoil, 1) * -1.4deg)) }
  48%  { transform: translateX(calc(var(--recoil, 1) * 4px)) rotate(calc(var(--recoil, 1) * 1deg)) }
  68%  { transform: translateX(calc(var(--recoil, 1) * -2px)) }
  100% { transform: translateX(0) }
}
@keyframes hitflash {
  0%   { filter: drop-shadow(0 6px 12px rgba(0,0,0,.65)) brightness(2.6) saturate(2.2) sepia(.5) hue-rotate(-35deg) }
  45%  { filter: drop-shadow(0 6px 12px rgba(0,0,0,.65)) brightness(1.5) saturate(1.6) sepia(.3) hue-rotate(-35deg) }
  100% { filter: drop-shadow(0 6px 12px rgba(0,0,0,.65)) }
}

/* landing a blow: lunge at the other side */
.cbt-art.swing { animation: lunge .3s cubic-bezier(.3,.8,.4,1) both; }
.cbt.you .cbt-art.swing { --lunge: 1; }
.cbt.foe .cbt-art.swing { --lunge: -1; }
@keyframes lunge {
  0%   { transform: translateX(0) scale(1) }
  35%  { transform: translateX(calc(var(--lunge, 1) * 12px)) scale(1.04) }
  100% { transform: translateX(0) scale(1) }
}
.cbt-art.mend .cutout { animation: mendflash .52s ease-out both; }
@keyframes mendflash {
  0%   { filter: drop-shadow(0 6px 12px rgba(0,0,0,.65)) brightness(1.7) saturate(1.4) hue-rotate(55deg) }
  100% { filter: drop-shadow(0 6px 12px rgba(0,0,0,.65)) }
}
.cbt-art.enrage .cutout { animation: enrageflash .7s ease-out both; }
@keyframes enrageflash {
  0%, 40% { filter: drop-shadow(0 0 16px rgba(200,60,60,.95)) brightness(1.8) saturate(2.4) }
  100%    { filter: drop-shadow(0 6px 12px rgba(0,0,0,.65)) }
}

/* impact burst — two crossed streaks plus a ring, drawn over the target */
.impact { position: absolute; left: 50%; top: 46%; width: 0; height: 0; pointer-events: none; }
.impact.burst::before, .impact.burst::after {
  content: ''; position: absolute; left: -34px; top: -2px; width: 68px; height: 4px; border-radius: 2px;
  background: linear-gradient(90deg, transparent, var(--burst, #f3e2b6), transparent);
  animation: slash .3s ease-out both;
}
.impact.burst::before { transform: rotate(28deg) }
.impact.burst::after  { transform: rotate(-24deg); animation-delay: .05s }
.impact.burst { animation: ring .38s ease-out both; }
.impact.k-enemy, .impact.k-bleed-tick { --burst: #ff8a7a }
.impact.k-flame { --burst: #ffab55 }
.impact.k-block { --burst: #a9c4e0 }
@keyframes slash { 0% { opacity: 0; transform: scaleX(.2) rotate(var(--r, 20deg)) } 25% { opacity: 1 } 100% { opacity: 0; transform: scaleX(1.5) } }
@keyframes ring {
  0%   { box-shadow: 0 0 0 2px var(--burst, #f3e2b6), 0 0 22px 6px rgba(243,226,182,.55); opacity: .95 }
  100% { box-shadow: 0 0 0 26px transparent, 0 0 34px 10px transparent; opacity: 0 }
}

/* floating amounts */
.floaters { position: absolute; inset: 0; pointer-events: none; overflow: visible; }
.floater {
  position: absolute; left: 50%; top: 40%; transform: translateX(-50%);
  font-family: var(--mono); font-size: calc(16px * var(--type-scale)); font-weight: 700;
  text-shadow: 0 1px 3px #000, 0 0 10px rgba(0,0,0,.9); white-space: nowrap;
  animation: floatUp .9s cubic-bezier(.2,.7,.3,1) both;
}
.floater.f-hit, .floater.f-dot { color: #f3e2b6 }
.floater.f-enemy, .floater.f-bleed-tick { color: #ff8a7a }
.floater.f-flame { color: #ffab55 }
.floater.f-heal { color: #a8d6a0 }
.floater.f-block, .floater.f-armor { color: #a9c4e0; font-size: calc(12px * var(--type-scale)) }
.floater.f-shred { color: #d8b4f0; font-size: calc(12px * var(--type-scale)) }
@keyframes floatUp {
  0%   { opacity: 0; transform: translate(calc(-50% + var(--dx, 0px)), 8px) scale(.7) }
  18%  { opacity: 1; transform: translate(calc(-50% + var(--dx, 0px)), -2px) scale(1.15) }
  100% { opacity: 0; transform: translate(calc(-50% + var(--dx, 0px)), -46px) scale(1) }
}
/* The amount is information, not decoration — it stays legible when motion is
   off. It simply sits still until the playback loop removes the node. */
body.reduce-motion .floater {
  animation: none !important;
  opacity: 1; transform: translate(calc(-50% + var(--dx, 0px)), -24px);
}

.cbt-name { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; font-size: calc(11.5px * var(--type-scale)); }
.cbt-name strong { font-family: var(--mono); font-size: calc(15px * var(--type-scale)); }
.cbt-name strong .max { font-size: calc(10.5px * var(--type-scale)); color: var(--muted); }

/* health gauge: ghost layer underneath shows the chunk the last blow took */
.health { position: relative; height: 11px; border-radius: 3px; background: rgba(10,10,7,.75); border: 1px solid rgba(255,255,255,.22); overflow: hidden; }
.health > u, .health > b { position: absolute; left: 0; top: 0; bottom: 0; display: block; text-decoration: none; border-radius: 2px; }
.health > u { background: rgba(255,255,255,.62); transition: width .35s ease-out; }
.health > b { background: linear-gradient(180deg, #a9c48f, #6f8a5e); transition: width .1s linear; box-shadow: 0 0 8px rgba(169,196,143,.45); }
.health.foe > b { background: linear-gradient(180deg, #d16b6b, #8E2D2D); box-shadow: 0 0 8px rgba(209,107,107,.45); }
.health.low > b { animation: hpLow .8s ease-in-out infinite; }
@keyframes hpLow { 0%, 100% { filter: brightness(1) } 50% { filter: brightness(1.7) } }
/* quarter marks so a change of a few points still reads as movement */
.health::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(90deg, transparent 0 calc(25% - 1px), rgba(10,10,7,.55) calc(25% - 1px) 25%);
}
.cchips { display: flex; flex-wrap: wrap; gap: 4px; }
.cchip { display: inline-flex; gap: 3px; align-items: baseline; padding: 2px 6px; border-radius: 999px; background: rgba(255,255,255,.07); font-size: calc(11.5px * var(--type-scale)); }
.cchip i { font-style: normal; color: var(--muted); }
.cchip b { font-family: var(--mono); }
.cchip.on { background: rgba(142,45,45,.3); }
.cchip.tier-1 { background: rgba(197,164,59,.28); }
.cchip.tier-2 { background: rgba(142,45,45,.4); }
.alert-banner { position: absolute; top: 40px; left: 0; right: 0; z-index: 3; text-align: center; padding: 5px; font-size: calc(11.5px * var(--type-scale)); background: rgba(142,45,45,.6); letter-spacing: .08em; }
.combat-lower { flex: 1; display: grid; grid-template-rows: auto auto 1fr; gap: 8px; padding: 8px 14px calc(12px + var(--safe-b)); min-height: 0; }
.combat-controls { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.mini-board { position: relative; width: 100%; aspect-ratio: 8 / 6; max-height: 22dvh; border-radius: 8px; background: rgba(10,10,7,.5); border: 1px solid var(--line-soft); }
.mini-item { position: absolute; border-radius: 3px; background: rgba(120,110,86,.5); }
.mini-item img { width: 100%; height: 100%; object-fit: contain; opacity: .9; }
.mini-item.fire { animation: fireflash .42s ease; }
.mini-item.heal { animation: healflash .42s ease; }
@keyframes fireflash { 0% { box-shadow: 0 0 0 2px var(--amber), 0 0 14px rgba(197,164,59,.9) } 100% { box-shadow: none } }
@keyframes healflash { 0% { box-shadow: 0 0 0 2px var(--green), 0 0 14px rgba(102,117,91,.9) } 100% { box-shadow: none } }
.combat-feed { overflow-y: auto; min-height: 0; display: grid; gap: 2px; align-content: start; font-size: calc(11.5px * var(--type-scale)); }
.feed-line { display: grid; grid-template-columns: 40px 1fr; gap: 6px; padding: 2px 0; border-bottom: 1px solid rgba(255,255,255,.04); }
.feed-line .ft { font-family: var(--mono); color: var(--muted); font-size: calc(11.5px * var(--type-scale)); }
.feed-line.k-hit .fx { color: #cfe0c0; }
.feed-line.k-enemy .fx { color: #eab8b8; }
.feed-line.k-heal .fx { color: #a9cfcb; }
.feed-line.k-alert .fx, .feed-line.k-ammo-out .fx { color: #e5b25a; }
.feed-line.k-bleed .fx, .feed-line.k-bleed-tick .fx { color: #f08a8a; }

/* ---------- debrief / reward / extract / result ---------- */
.debrief-body, .reward-body, .extract-body { flex: 1; overflow-y: auto; padding: 14px 16px; display: grid; gap: 12px; align-content: start; }
.outcome-badge { display: grid; gap: 2px; padding: 12px; border-radius: 10px; text-align: center; }
.outcome-badge.win { background: rgba(102,117,91,.24); border: 1px solid rgba(102,117,91,.5); }
.outcome-badge.lose { background: rgba(142,45,45,.24); border: 1px solid rgba(142,45,45,.5); }
.outcome-badge strong { font-size: calc(19px * var(--type-scale)); }
.outcome-badge small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.cause-list { display: grid; gap: 7px; }
.cause-list li { position: relative; padding: 9px 11px 9px 30px; border-radius: 8px; background: rgba(255,255,255,.04); font-size: calc(12.5px * var(--type-scale)); line-height: 1.55; }
.cause-list li::before { position: absolute; left: 11px; top: 9px; font-weight: 700; }
.cause-list li.good::before { content: "+"; color: var(--green); }
.cause-list li.bad::before { content: "!"; color: var(--bleed); }
.carry { padding: 11px; border-radius: 10px; border: 1px solid var(--line-soft); background: rgba(28,27,20,.7); display: grid; gap: 8px; }
.carry-rows { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.carry-rows > div { display: grid; gap: 1px; justify-items: center; }
.carry-rows span { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.carry-rows strong { font-size: calc(13px * var(--type-scale)); }
.debrief-detail { display: grid; gap: 10px; }
.dd-rows { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.dd-rows > div { display: flex; justify-content: space-between; padding: 7px 9px; border-radius: 7px; background: rgba(255,255,255,.04); font-size: calc(11.5px * var(--type-scale)); }
.dd-rows span { color: var(--muted); }
.contrib { display: grid; gap: 6px; }
.contrib-row { display: grid; grid-template-columns: 34px 1fr auto; gap: 8px; align-items: center; padding: 7px; border-radius: 8px; background: rgba(255,255,255,.04); }
.contrib-row img { height: 30px; object-fit: contain; }
.contrib-row strong { font-size: calc(12px * var(--type-scale)); display: block; }
.contrib-row small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.contrib-num { font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); color: var(--amber); }

/* ---------- reward ----------
   A beat, not a receipt: the district behind you, the number you just earned
   counting up, and the stage read as pips so you know how much is left. */
.reward-bg, .extract-bg {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-size: cover; background-position: 50% 46%; filter: saturate(.5) brightness(.5);
}
.reward-veil, .extract-veil {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(96% 42% at 50% 34%, rgba(197,164,59,.13), rgba(10,10,7,0) 72%),
    linear-gradient(180deg, rgba(10,10,7,.9) 0%, rgba(10,10,7,.72) 40%, rgba(9,9,6,.96) 100%);
}
.screen-reward .progress-strip, .screen-extract .progress-strip { position: relative; z-index: 1; }
.reward-body { position: relative; z-index: 1; align-content: center; justify-items: center; text-align: center; gap: 14px; }
.reward-stamp { display: grid; gap: 3px; justify-items: center; }
.reward-stamp h2 { font-size: calc(21px * var(--type-scale)); }
.reward-sub { font-size: calc(11.5px * var(--type-scale)); color: var(--dust); }
.reward-amount {
  display: flex; align-items: baseline; gap: 8px; padding: 6px 22px; border-radius: 14px;
  border: 1px solid rgba(197,164,59,.34); background: rgba(197,164,59,.08);
  box-shadow: 0 0 34px rgba(197,164,59,.14), inset 0 0 22px rgba(197,164,59,.06);
  animation: rewardPop .34s cubic-bezier(.2,1.3,.5,1) both;
}
@keyframes rewardPop { from { transform: scale(.9); opacity: 0 } to { transform: none; opacity: 1 } }
.reward-amount .ra-num {
  font-size: calc(40px * var(--type-scale)); color: var(--amber); line-height: 1.1;
  font-variant-numeric: tabular-nums; text-shadow: 0 0 26px rgba(197,164,59,.45);
}
.reward-amount span { font-size: calc(12px * var(--type-scale)); color: var(--dust); }
.reward-pips { display: flex; gap: 5px; }
.reward-pips i { width: 22px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.12); }
.reward-pips i.done { background: rgba(102,117,91,.85); }
.reward-pips i.now { background: var(--amber); box-shadow: 0 0 10px rgba(197,164,59,.6); }
.reward-left { font-size: calc(12px * var(--type-scale)); color: var(--dust); }
.reward-meta { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; width: 100%; max-width: 300px; }
.reward-meta > div { display: grid; gap: 2px; padding: 8px 10px; border-radius: 9px; background: rgba(255,255,255,.05); }
.reward-meta span { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.reward-meta strong { font-size: calc(14px * var(--type-scale)); font-family: var(--mono); }
.reward-actions, .extract-actions { position: relative; z-index: 1; display: grid; gap: 8px; padding: 0 16px calc(18px + var(--safe-b)); }

/* ---------- extract ----------
   Bank it or push it. Two opposed cards, not a stat table — the thing you keep
   and the thing you are betting it on, each with its own commit button. */
/* The commit buttons live inside the two cards, so this screen has no sticky
   action bar to carry the safe-area inset — it has to carry it itself. */
.extract-body { position: relative; z-index: 1; padding-bottom: calc(18px + var(--safe-b)); }
.extract-body h2 { font-size: calc(21px * var(--type-scale)); margin-bottom: 2px; }
.extract-banked {
  display: grid; gap: 8px; padding: 12px 14px; border-radius: 13px;
  border: 1px solid rgba(197,164,59,.4); background: linear-gradient(160deg, rgba(197,164,59,.15), rgba(16,15,10,.9));
}
.eb-hero { display: flex; align-items: baseline; gap: 8px; }
.eb-hero strong { font-size: calc(34px * var(--type-scale)); color: var(--amber); font-variant-numeric: tabular-nums; line-height: 1; }
.eb-hero span { font-size: calc(11.5px * var(--type-scale)); color: var(--dust); }
.eb-rows { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.eb-rows > div { display: grid; gap: 1px; padding: 7px 9px; border-radius: 8px; background: rgba(0,0,0,.3); }
.eb-rows span { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.eb-rows strong { font-size: calc(12.5px * var(--type-scale)); }
.extract-choice {
  display: grid; gap: 8px; padding: 12px; border-radius: 13px;
  border: 1px solid var(--line-soft); background: rgba(18,17,12,.86);
}
.extract-choice h3 { font-size: calc(15px * var(--type-scale)); }
.extract-choice.stay { border-color: rgba(197,164,59,.34); }
.extract-choice.go { border-color: rgba(102,117,91,.46); }
.ec-note { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); line-height: 1.55; }
.ec-rows { display: grid; gap: 5px; }
.ec-rows > div { display: flex; justify-content: space-between; gap: 10px; padding: 8px 11px; border-radius: 8px; background: rgba(255,255,255,.04); font-size: calc(12.5px * var(--type-scale)); }
.ec-rows span { color: var(--muted); }
.ec-rows .r-advantage strong { color: #cfe0c0; }
.ec-rows .r-close strong { color: #eed99b; }
.ec-rows .r-danger strong, .ec-rows .r-no_attack strong { color: #f0b9b9; }

/* See the note on .screen-brief — .screen already positions this. */
.result-bg { position: absolute; inset: 0; background-size: cover; background-position: center; }
.result-veil { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(10,10,7,.82), rgba(10,10,7,.97)); }
.result-body { position: relative; flex: 1; overflow-y: auto; padding: 20px 16px 12px; display: grid; gap: 10px; align-content: start; }
.result-body h2 { font-size: calc(26px * var(--type-scale)); }
.result-body h2.win { color: #cfe0c0; }
.result-body h2.lose { color: #f2b6b6; }
.score-hero { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.score-hero > span { font-size: calc(12px * var(--type-scale)); color: var(--muted); }
.score-num {
  font-size: calc(40px * var(--type-scale)); color: var(--amber); font-family: var(--mono);
  font-variant-numeric: tabular-nums; text-shadow: 0 0 26px rgba(197,164,59,.35);
}
/* Only shows when the run actually beat the stored best, so it can afford to
   shout — it is the one moment on this screen worth looking up for. */
.score-record {
  display: grid; gap: 1px; align-self: center; padding: 5px 11px; border-radius: 999px;
  border: 1px solid rgba(224,192,105,.7); background: rgba(197,164,59,.18);
  animation: recordPop .4s cubic-bezier(.2,1.3,.5,1) both .35s;
}
@keyframes recordPop { from { opacity: 0; transform: scale(.86) } to { opacity: 1; transform: none } }
.score-record b { font-size: calc(11.5px * var(--type-scale)); color: #f5e7b6; }
.score-record small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); }
.token-gain { display: flex; justify-content: space-between; padding: 9px 12px; border-radius: 8px; background: rgba(197,164,59,.14); font-size: calc(12.5px * var(--type-scale)); }
.score-rows { display: grid; gap: 5px; }
.score-rows > div { display: flex; justify-content: space-between; gap: 10px; font-size: calc(11.5px * var(--type-scale)); padding: 6px 9px; border-radius: 6px; background: rgba(255,255,255,.04); }
.score-rows span { color: var(--muted); }
.tag-row { display: flex; flex-wrap: wrap; gap: 5px; }
.final-pack { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; }
.fp-item { display: grid; gap: 2px; justify-items: center; padding: 6px 2px; border-radius: 7px; background: rgba(255,255,255,.04); }
.fp-item img { height: 26px; object-fit: contain; }
.fp-item small { font-size: calc(11.5px * var(--type-scale)); color: var(--muted); text-align: center; line-height: 1.2; }
.result-actions { position: relative; display: grid; gap: 8px; padding: 0 16px calc(18px + var(--safe-b)); }

/* ---------- coach (progressive onboarding) ---------- */
/* The layer never eats input. A player who wants to ignore the lesson and press
   something else always can — only the card itself is interactive. */
.coach-layer { position: fixed; inset: 0; z-index: 90; pointer-events: none; }
.coach-layer[hidden] { display: none; }

/* One element does the whole spotlight: the huge shadow spread dims everything
   outside its own box, so the target stays at full brightness without having to
   be re-parented or given a z-index it would not otherwise survive. */
.coach-spot {
  position: fixed; pointer-events: none;
  border: 2px solid var(--amber);
  box-shadow: 0 0 0 9999px rgba(6,6,4,.74), 0 0 18px 2px rgba(197,164,59,.55), inset 0 0 12px rgba(197,164,59,.25);
  transition: left .2s ease, top .2s ease, width .2s ease, height .2s ease;
}
.coach-layer.no-target .coach-spot { display: none; }
body:not(.reduce-motion) .coach-spot { animation: coachPulse 2s ease-in-out infinite; }
@keyframes coachPulse {
  0%, 100% { box-shadow: 0 0 0 9999px rgba(6,6,4,.74), 0 0 18px 2px rgba(197,164,59,.55), inset 0 0 12px rgba(197,164,59,.25); }
  50%      { box-shadow: 0 0 0 9999px rgba(6,6,4,.74), 0 0 26px 5px rgba(197,164,59,.8),  inset 0 0 12px rgba(197,164,59,.25); }
}

/* Anchored to the control being explained — position is written by coach.js. */
.coach-card {
  position: fixed; pointer-events: auto;
  background: rgba(20,20,14,.98); border: 1px solid var(--amber); border-radius: 13px;
  padding: 12px 13px; display: grid; gap: 5px;
  box-shadow: 0 10px 34px rgba(0,0,0,.7);
  animation: coachIn .18s ease;
}
@keyframes coachIn { from { opacity: 0; transform: translateY(-4px) } to { opacity: 1; transform: none } }
body.reduce-motion .coach-card { animation: none; }
/* She is the voice of every lesson, so she heads every card. */
.coach-who { display: flex; align-items: center; gap: 9px; padding-bottom: 7px; border-bottom: 1px solid rgba(197,164,59,.22); }
.coach-face {
  width: 42px; height: 42px; flex: 0 0 auto; border-radius: 50%;
  object-fit: cover;
  border: 1px solid rgba(197,164,59,.5); background: rgba(197,164,59,.08);
}
/* First card only: she actually turns up — head, shoulders and upper chest —
   before shrinking to a face chip for every lesson after it. 96x112 is the
   plate's own 270x315 aspect, so `contain` fits it exactly with no letterbox. */
.coach-face.big {
  width: 96px; height: 112px; border-radius: 10px 10px 4px 4px;
  object-fit: contain; object-position: 50% 0;
  border-color: transparent; background: none;
  filter: drop-shadow(0 4px 10px rgba(0,0,0,.6));
}
.coach-who-txt { display: grid; gap: 1px; min-width: 0; }
.coach-who-txt strong { font-size: calc(13px * var(--type-scale)); color: #f0dfa8; }
.coach-code { font-family: var(--mono); font-size: calc(11.5px * var(--type-scale)); letter-spacing: .16em; color: var(--amber); opacity: .9; }
.coach-card h3 { font-size: calc(14.5px * var(--type-scale)); line-height: 1.35; }
/* Her lines are written with their own line breaks — keep them. */
.coach-body { font-size: calc(12px * var(--type-scale)); color: var(--dust); line-height: 1.6; white-space: pre-line; }
.coach-task {
  margin-top: 2px; padding: 5px 8px; border-radius: 7px;
  background: rgba(197,164,59,.14); border: 1px solid rgba(197,164,59,.35);
  font-size: calc(11.5px * var(--type-scale)); color: #f0dfa8; font-weight: 600;
}
.coach-actions { display: flex; gap: 8px; justify-content: space-between; align-items: center; margin-top: 2px; }
.coach-skip { font-size: calc(11.5px * var(--type-scale)); opacity: .75; text-decoration-color: rgba(197,164,59,.4); }
.coach-card.done { border-color: var(--green); }
.coach-card.done .coach-task { background: rgba(102,117,91,.28); border-color: var(--green); color: #cfe0c0; }

/* Little pointer between the card and the thing it is talking about. */
.coach-caret {
  position: fixed; width: 0; height: 0; margin-left: -7px; pointer-events: none;
  border-left: 7px solid transparent; border-right: 7px solid transparent;
}
.coach-caret.up { border-bottom: 7px solid var(--amber); margin-top: -7px; }
.coach-caret:not(.up) { border-top: 7px solid var(--amber); }
.coach-layer.no-target .coach-caret { display: none; }

/* ---------- small screens ---------- */
@media (max-height: 700px) {
  .home-rail { top: 8px; }
  .home-actions { padding-top: 14px; }
  .fo-side .cutout { height: 100px; }
  .combat-stage { height: 34dvh; min-height: 200px; }
  .intro-figure { min-height: 0; }
  .screen-intro { grid-template-rows: 34dvh 1fr auto; }
}
@media (max-width: 359px) {
  .home-actions { gap: 8px; }
  .dia { width: 66px; }
  .dia-face { width: 66px; height: 66px; }
  .dia.big, .dia.big .dia-face { width: 84px; height: auto; }
  .dia.big .dia-face { height: 84px; }
  .rail-btn { width: 52px; }
  .rn-label { width: 100px; }
  .tray-card { width: 66px; }
  .final-pack { grid-template-columns: repeat(4, 1fr); }
  .pack-actions { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 700px) and (min-height: 620px) {
  .frame { max-width: 480px; height: min(100dvh, 940px); margin-top: max(0px, calc((100dvh - 940px) / 2)); border-radius: 18px; border: 1px solid rgba(255,255,255,.06); }
  body { background: radial-gradient(90% 60% at 50% 0%, #1a1a14, #0a0a07); }
}
/* A phone turned sideways leaves ~340px of height. The mini pack board is a
   static mirror of the loadout the player just built, not live information, so
   it is what gives way — spending its space on the fighters and the event feed,
   which are the two things that explain the fight. Comes after the max-height
   block above so it wins on source order at equal specificity. */
@media (orientation: landscape) and (max-height: 560px) {
  .combat-stage { height: 46dvh; min-height: 0; }
  .combat-lower { grid-template-rows: auto 1fr; row-gap: 6px; padding-top: 6px; }
  .mini-board { display: none; }
  .fo-side .cutout { height: 88px; }
}

:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
