/* shared/ui.css -- the stylesheet of the game UI. Linked by mock/index.html and by client/ (the milestone 5
   client), so the two cannot drift. Moved verbatim out of the mock's <style> block; the notes below are
   Iceberg's and still describe it. */
/* ======================================================================
   Admiral Xorrbo's Challenge — mock UI
   Palette and system taken from design/rules.html :root and
   design/ui-design.html Section 1 (dark board #12151C, light panels
   #F4F5F7, 8px grid, 44px touch targets, capability colors).

   ------------------------------------------------------------------
   ICEBERG — VISUAL SYSTEM NOTES (visual pass, see mock/ for the rest)
   ------------------------------------------------------------------
   1. CAPABILITY COLOR TABLE. Jim reads rules.html Figures 1, 2 and 7, so
      five of the eight capabilities use its exact CSS colors; only the
      three that would otherwise collide with a player color are retuned,
      plus the base-only "cooldown" slot which the rules document has no
      color for at all (it never had its own glyph there):
        speed    #0072B2  (rules.html)    shield   #1E8A5E  (rules.html)
        laser    #C62B38  (rules.html)    sensor   #8A6BC1  (rules.html)
        stealth  #5B6270  (rules.html)
        range    #8C9A2E  olive-khaki     tracking #C2559B  rose-magenta
                 (retuned — rules.html's           (retuned — rules.html's
                 sensor/laser-range color           tracking color #A6337F
                 collides with P3 #A6337F)          collides with P3 too)
        mine     #9C6B33  bronze/ochre    cooldown #5C6B8A  steel blue-gray
                 (retuned — rules.html's            (base-only slot, own
                 mine color #D2521E                 glyph — no longer
                 collides with P2)                  borrows the mine glyph)
      Every one of these is also paired with its own glyph (capGlyph()) so
      no state ever depends on color alone — the color table above is a
      convenience for players with full color vision, not the mechanism.
   2. SILHOUETTES (robotSilhouettePath). Chassis shape = the capability
      with the most tokens on that robot (ties broken by this fixed
      precedence, weapon/utility role beats raw mobility):
        laser > mine > sensor > tracking > shield > range > stealth > speed
      Shapes, one per capability (ui-design Fig 3B names in parens):
        speed=wedge (Courier) · shield=hex (Hauler) · laser=spiked spike
        (Gunship) · sensor=dish-on-ring (Watcher) · stealth=dashed facet
        (Ghost) · mine=squat rounded chassis (Sapper) · range=octagon
        (new — a "scope housing") · tracking=pentagon (new — a "lock").
      A BARE robot (no tokens) never reuses any of these — it is always
      the hollow, dashed, translucent player-color wash per ui-design
      Fig 3's requirement B, on the board, in replay, on squad cards and
      live on the configuration rows as the robot is being built.
   3. TERRAIN (ui-design Fig 5): dirt is clean (no overlay — its own
      "pattern" is the absence of one), rock is angular chips, sand is
      fine horizontal drifts, marsh is a wavy reed line — four *kinds*
      of mark, not four densities of the same mark, so a remembered
      (45% opacity) tile still reads by shape once color/lightness are
      washed out, and never gets mistaken for the flat gray fog stipple
      (which uses none of these four patterns).

   ------------------------------------------------------------------
   ICEBERG — R82 ADDENDUM (action window, waypoints, bomb dial)
   ------------------------------------------------------------------
   4. ACTION WINDOW. One shared overlay chrome (#overlay-actionwin) for
      robot orders, repair, reconfigure and the bomb aim — a sticky header
      with a single close (×), the order's own mini-map up top (built from
      the same renderMapStaticParts()/silhouettes as the main board, so
      nothing here is a second visual language), then the controls. It is
      deliberately heavier chrome than the old inline composer strip (full
      header bar, own scroll region, full-screen on phone) so committing an
      order reads as its own focused step, not a popover stacked on the map.
   5. WAYPOINTS. A route's intermediate points are numbered accent-blue
      pins; the final destination is always the distinct good-green
      diamond-filled pin, on both the mini-map and the route strip, so
      "where it ends up" never has to be inferred by counting. An unarmed
      robot's window skips the weapons-free/target sections entirely and
      says so in words ("Unarmed — travels only") rather than showing a
      disabled control with no visible reason.
   6. BOMB DIAL. The angle track's legal/illegal bands are painted only
      through the --band-bg custom property (never by touching the
      slider's DOM node, min/max or value, so a live drag is never
      interrupted) — legal is the reserved success background, illegal
      is the reserved danger background PLUS a diagonal hatch, so the
      distinction survives on a grayscale screen. Bearing gets three
      redundant cues, from cheapest to richest: the numeral, a 16-point
      compass word next to it (compassWord(), e.g. "ESE"), and a fixed
      N/E/S/W rose pinned over the map confirming it is drawn north-up —
      plus the actual aim line from base to impact tile, dashed in the
      same legal/illegal color as the blast preview, so "bearing 200°"
      is never just a number a player has to picture unassisted.

   ------------------------------------------------------------------
   ICEBERG — R84 ADDENDUM (the three-turn horizon)
   ------------------------------------------------------------------
   7. HORIZON vs FOG — three independent facts, three independent channels.
      A tile can be unexplored / remembered / observed (fog) AND separately
      in range / out of range for this order (horizon); the two must never
      collapse into "one more shade of dark." Fog keeps its existing
      language untouched (flat gray stipple / ~45% opacity / full). The
      horizon's primary signal is a traced boundary line (dashed, light
      neutral #F4F5F7, drawn once as a single <path> from the routing cost
      field — see tileInPlotRange() in renderRobotWindowMap) around the
      reachable region, so the shape reads at a glance without depending on
      opacity at all. Out-of-range tiles get, at most, a faint neutral
      var(--board-bg) scrim (0.18 — well below fog/remembered's darkening)
      and ONLY if they're already explored; a fog tile is already maximally
      muted by its own treatment, so it is left alone rather than stacking
      a second "hidden" signal on top of the first. Net result at any
      overlap: observed+in-range is full brightness, observed+out-of-range
      is barely dimmed, remembered+in-range is fog's usual 45%, remembered
      +out-of-range is dimmed a little further than that — four readable
      steps, plus the line, and fog's own stipple never gets touched.
   ====================================================================== */
:root{
  --ink:#1B1E24; --ink2:#5B6270; --ink3:#8A909C;
  --rule:#D8DCE3; --panel:#F4F5F7; --accent:#0072B2;
  --board-bg:#12151C; --board-panel:#1C2029; --statusbar:#0B0E14;
  --p1:#0066B3; --p2:#D2521E; --p3:#A6337F; --p4:#3D2C6D;
  --dirt:#C8A67E; --rock:#848B9A; --sand:#AE9947; --marsh:#4E6A39;
  --gold:#E8B84B; --silver:#B8BFC9; --diamond:#7FD4E8; --emerald:#5BB47E;
  /* Capability palette — see "VISUAL SYSTEM NOTES" comment above for the
     derivation and the silhouette/tie-break rules that go with it. */
  --cap-speed:#0072B2; --cap-shield:#1E8A5E; --cap-laser:#C62B38; --cap-range:#8C9A2E;
  --cap-sensor:#8A6BC1; --cap-stealth:#5B6270; --cap-mine:#9C6B33; --cap-tracking:#C2559B;
  --cap-cooldown:#5C6B8A;
  --danger:#C62B38; --danger-bg:#FBEDEE; --danger-border:#EBBFC3;
  --good:#1E8A5E; --good-bg:#EAF7F0;
  --warn-bg:#FFF7E6; --warn-border:#E8B84B; --warn-text:#7A5A0F;
  --white:#FFFFFF;
  --radius:4px;
  color-scheme: light;
}
*{box-sizing:border-box}
body{
  font-family:-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  color:var(--ink); background:var(--panel); margin:0;
}
button{font-family:inherit}
.mono{font-family:"Cascadia Mono",Consolas,"SF Mono","Roboto Mono",Menlo,monospace}
h1,h2,h3,h4{margin:0}
.hidden{display:none !important}
button{cursor:pointer}
.btn{
  appearance:none;border:1px solid var(--rule);background:#fff;color:var(--ink);
  border-radius:var(--radius);padding:8px 14px;font-size:13px;font-weight:700;
  min-height:44px;min-width:44px;
}
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}
.btn.danger{background:var(--danger);border-color:var(--danger);color:#fff}
.btn.ghost{background:transparent;border-color:transparent}
.btn.small{min-height:44px;padding:4px 10px;font-size:12px}
.pill{display:inline-flex;align-items:center;gap:4px;border-radius:999px;padding:2px 8px;font-size:11px;font-weight:700}
.badge-carried{background:var(--good-bg);color:var(--good);border:1px solid var(--good);font-size:10px;font-weight:800;letter-spacing:.03em;border-radius:3px;padding:1px 6px}
.kicker{font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--ink3)}

/* ---------------- app shell / screens ---------------- */
#app{min-height:100vh;position:relative}
.screen:not(.active){display:none !important}
.screen{min-height:100vh}

/* ================= CONFIG SCREEN ================= */
#screen-config{max-width:1180px;margin:0 auto;padding:16px}
.cfg-header{background:var(--ink);color:#fff;border-radius:6px;padding:14px 18px;display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap}
.cfg-header h1{font-size:17px}
.cfg-header p{margin:4px 0 0;font-size:12.5px;color:#B8BFC9;max-width:520px}
.token-counter{text-align:right}
.token-counter .num{font-size:26px;font-weight:800;color:var(--diamond)}
.token-counter .lbl{font-size:10px;font-weight:700;letter-spacing:.08em;color:#8A909C}
.token-pips{display:flex;gap:4px;margin-top:4px}
.token-caption{font-size:10px;color:#8A909C;margin-top:3px;font-weight:700}
.token-pip{width:14px;height:14px;border-radius:3px;background:#3D4450}
.token-pip.filled{background:var(--diamond)}

.cfg-body{display:grid;grid-template-columns:190px 1fr 260px;gap:14px;margin-top:14px}
.cfg-palette{background:var(--panel);border:1px solid var(--rule);border-radius:6px;padding:10px}
.cfg-palette h4{font-size:11px;letter-spacing:.08em;color:var(--ink2);margin-bottom:8px}
/* Round 8 (Jim: "the laser damage box is bigger than speed... all tokens
   should be the same size box") -- a bare flex button shrinks to fit its
   own text, so a short label ("Sensor") rendered narrower than a long one
   ("Sensor/laser range"). width:100% forces every chip to the palette
   column's full width regardless of label length. */
.cap-chip{display:flex;justify-content:space-between;align-items:center;gap:6px;width:100%;color:#fff;border-radius:4px;padding:9px 10px;margin-bottom:6px;font-size:12.5px;font-weight:700;min-height:44px;border:2px solid transparent}
.cap-chip .short{font-weight:600;font-size:11px;opacity:.85}
.cap-chip.selected{outline:3px solid #1B1E24;outline-offset:1px}
.cap-chip[disabled]{opacity:.35;cursor:not-allowed}
.cap-glyph{width:16px;height:16px;flex:0 0 auto}

.cfg-rows{display:flex;flex-direction:column;gap:10px}
.robot-row{background:#fff;border:1px solid var(--rule);border-radius:6px;padding:10px 12px}
.robot-row.base-row{background:#FAFBFC}
.robot-row-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.robot-row-head .rname{font-weight:800;font-size:14px}
.robot-row-head .rename-btn{font-size:11px;color:var(--accent);font-weight:700;background:none;border:none;min-height:44px;min-width:44px;padding:0 8px}
.robot-row-head input.rename-input{font-size:13px;font-weight:700;padding:3px 6px;border:1px solid var(--accent);border-radius:3px}
.permanent-tag{font-size:10.5px;color:#fff;background:var(--danger);font-weight:800;letter-spacing:.03em;border-radius:3px;padding:2px 8px;display:inline-flex;align-items:center;gap:4px}
.slot-strip{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0}
.slot-btn{flex:1 1 0;min-width:44px;min-height:44px;border-radius:4px;border:2px dashed var(--rule);background:#fff;color:var(--ink3);font-size:11px;font-weight:700;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px}
.slot-btn.filled{border-style:solid;color:#fff}
.slot-btn .n{font-size:9px;opacity:.85;font-weight:600}
.readout-line{font-size:12px;color:var(--ink2);margin-top:2px}
.readout-line b{color:var(--ink)}
.order-strip-row{display:flex;align-items:center;gap:6px;margin-top:8px;font-size:11px;flex-wrap:wrap}
.order-prefix{color:var(--ink3);font-style:italic}
.order-chip{display:flex;align-items:center;gap:4px;color:#fff;border-radius:3px;padding:5px 8px;font-weight:700;font-size:11px}
.order-chip .updn{display:flex;flex-direction:row;gap:2px;margin-left:4px}
.order-chip button{min-height:44px;min-width:44px;padding:0;font-size:11px;line-height:1;background:rgba(0,0,0,.25);color:#fff;border:none;border-radius:2px}
.nothing-to-order{font-size:11px;color:var(--ink3);font-style:italic}

.cfg-guidance{background:#EAF4FB;border:1px solid var(--accent);border-radius:6px;padding:14px}
.cfg-guidance h4{font-size:11px;letter-spacing:.08em;color:var(--accent);margin-bottom:10px}
.guide-fact{margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid #B8D4E8}
.guide-fact:last-child{border:none;margin-bottom:0;padding-bottom:0}
.guide-fact .t{font-weight:700;font-size:12.5px;margin-bottom:3px}
.guide-fact .d{font-size:11.5px;color:var(--ink2);line-height:1.4}
.guide-fact.warn .t{color:var(--danger)}

.cfg-footer{margin-top:14px;display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;border-radius:6px;padding:12px 16px}
.cfg-footer.unspent{background:var(--danger-bg);border:1px solid var(--danger-border)}
.cfg-footer.ok{background:var(--good-bg);border:1px solid var(--good)}
.cfg-footer .msg b{display:block;color:var(--danger)}
.cfg-footer.ok .msg b{color:var(--good)}
.cfg-footer .msg span{font-size:12px;color:var(--ink2)}
#cfg-mobile-pager{display:none}

/* ================= BOARD SCREEN ================= */
#screen-board{display:grid;grid-template-columns:1fr 320px;grid-template-rows:auto 1fr auto;height:100vh;gap:0}
.topbar{grid-column:1/3;background:var(--ink);color:#fff;display:flex;align-items:center;gap:14px;padding:6px 12px;min-height:56px;flex-wrap:wrap}
.topbar .menu-btn{background:#2A2F3A;color:#fff;border:none;border-radius:4px;min-height:44px;min-width:44px;font-size:16px}
.delivered-tracker{display:flex;gap:14px;flex:1;overflow-x:auto}
.delivered-row{display:flex;align-items:center;gap:5px;white-space:nowrap}
.delivered-row .dot{width:10px;height:10px;border-radius:50%}
.dot{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:6px;vertical-align:middle}
.recap-table{width:100%;border-collapse:collapse;font-size:12px;margin-bottom:8px}
.recap-table th{text-align:left;font-size:10px;letter-spacing:.04em;color:var(--ink3);text-transform:uppercase;padding:4px 6px;border-bottom:1px solid var(--rule)}
.recap-table td{padding:5px 6px;border-bottom:1px solid var(--rule)}
.delivered-row .name{font-size:11px;font-weight:700;color:#B8BFC9;max-width:9rem;overflow:hidden;text-overflow:ellipsis}
.delivered-row.you .name{color:#fff}
.res-pip{width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center}
.one-away{color:#FF4757;font-weight:800;font-size:10.5px}
.turn-box{text-align:right}
.turn-box .lbl{font-size:9px;letter-spacing:.08em;color:#8A909C;font-weight:700}
.turn-box .val{font-size:15px;font-weight:800}
.timer-btn{background:none;border:1px solid #3D4450;color:#fff;border-radius:4px;padding:4px 10px;font-weight:800;font-family:"Cascadia Mono",Consolas,monospace;min-height:44px;min-width:44px}

.map-wrap{position:relative;background:var(--board-bg);overflow:hidden;display:flex;align-items:center;justify-content:center}
#board-svg{width:100%;height:100%;display:block;touch-action:none}
.quad-label{fill:#B8BFC9;font-size:16px;font-weight:700;letter-spacing:.04em}
.bomb-illegal-flash{animation:bomb-illegal-pulse 0.9s ease-in-out 2}
@keyframes bomb-illegal-pulse{0%,100%{opacity:1}50%{opacity:0.25}}

.squad-panel{background:var(--panel);border-left:1px solid var(--rule);overflow-y:auto;padding:10px;display:flex;flex-direction:column;gap:8px}
.squad-sheet-handle{display:none}
.unit-card{background:#fff;border:1px solid var(--rule);border-radius:6px;padding:8px 10px;cursor:pointer}
.unit-card.selected{border-color:var(--accent);box-shadow:0 0 0 2px rgba(0,114,178,.25)}
.unit-card.damaged{border-left:3px solid var(--danger)}
.unit-card.destroyed{opacity:.55}
.unit-card-head{display:flex;align-items:center;gap:8px}
.unit-dot{width:26px;height:26px;display:flex;align-items:center;justify-content:center;color:#fff;font-size:10px;font-weight:800;flex:0 0 auto}
.unit-dot.letter-badge{border-radius:5px}
.robot-row-head .robot-icon{width:26px;height:26px;flex:0 0 auto}
.unit-card-head .uname{font-weight:800;font-size:13px;flex:1}
.unit-card-head .uspeed{font-size:10.5px;color:var(--ink2)}
/* R85 (Jim: "the tokens should be the same size in the side window") — a
   token is a fixed quantity, so it is drawn a fixed size everywhere it
   appears; a 3-token robot's row is simply shorter than a 5-token robot's,
   which is what makes them comparable at a glance instead of both being
   stretched to fill their card. */
.slot-pips{display:flex;flex-wrap:wrap;gap:4px;margin:6px 0 4px}
.slot-pip{flex:0 0 22px;width:22px;height:18px;border-radius:3px;background:#DFE3E9;position:relative;display:flex;align-items:center;justify-content:center;overflow:hidden}
.slot-pip .pip-hatch{position:absolute;inset:0;background:repeating-linear-gradient(45deg,#B7BEC9 0 2px,transparent 2px 5px)}
.slot-pip.half .pip-fill{position:absolute;left:0;top:0;bottom:0;width:50%}
.slot-pip.half .pip-hatch{left:50%;width:50%;right:0}
.slot-pip .pip-glyph{position:relative;z-index:1}
.dmg-line{font-size:11px;color:var(--ink2);display:flex;justify-content:space-between}
.dmg-line b{color:var(--danger)}
.order-line{font-size:11px;color:var(--ink2);margin-top:4px}
.carried-badge{display:inline-block;background:#EAF4FB;color:var(--accent);border:1px solid var(--accent);font-size:9px;font-weight:800;border-radius:3px;padding:1px 5px;margin-left:4px}
.safezone-badge{display:inline-block;background:var(--good-bg);color:var(--good);border:1px solid var(--good);font-size:9.5px;font-weight:800;border-radius:3px;padding:1px 6px;margin-top:4px}
.half-speed-badge{display:inline-block;background:var(--danger-bg);color:var(--danger);border:1px solid var(--danger);font-size:9.5px;font-weight:800;border-radius:3px;padding:1px 6px;margin:2px 0}
.cargo-tab{display:inline-flex;align-items:center;gap:3px;font-size:9.5px;font-weight:800;border-radius:3px;padding:1px 6px;margin-top:4px}
.base-card{background:#fff;border:1px solid var(--rule);border-radius:6px;padding:8px 10px}
.repair-card{background:var(--good-bg);border:1px solid var(--good);border-radius:6px;padding:8px 10px}
.card-actions{display:flex;gap:6px;margin-top:6px;flex-wrap:wrap}

.bottombar{grid-column:1/3;background:var(--panel);border-top:1px solid var(--rule);display:flex;align-items:center;gap:14px;padding:8px 14px;min-height:64px;flex-wrap:wrap}
.bottombar .ordered-count{font-size:12px;color:var(--ink2);white-space:nowrap}
.bottombar .lastturn{flex:1;font-size:12px;color:var(--ink);min-width:180px}
.bottombar .lastturn b{color:var(--ink)}
.bottombar .lastturn .replay-link{color:var(--accent);font-weight:800;background:none;border:none;min-height:44px;min-width:44px;padding:0 6px;display:inline-flex;align-items:center;vertical-align:middle}

/* action window (R82: robot orders, repair, reconfigure, bomb aim) */
.actionwin-map-wrap{background:var(--board-bg);border-radius:6px;overflow:hidden;margin-bottom:10px;position:relative}
/* R85 (Jim: "the individual window loses some text") — the map is square
   (the board's own aspect ratio) and takes whatever space its column
   leaves it, up to a sensible cap, rather than the old fixed 360px that
   let it claim the whole window and push every control below the fold. */
.actionwin-map-wrap svg{width:100%;aspect-ratio:1/1;max-height:min(58vh,520px);display:block}
/* R85: the order window's map and its controls sit side by side on a wide
   screen — the map is context for the order, not more important than the
   controls that make it, so neither should have to push the other off
   screen. actionwin-split is added only for the robot-order window (see
   renderRobotOrderWindow); repair/reconfigure/bomb stay at the narrower
   default width, since none of them has a controls column this deep. */
.actionwin-panel.actionwin-split{max-width:1060px}
.actionwin-layout{display:flex;gap:18px;align-items:flex-start}
.actionwin-map-col{flex:1 1 0;min-width:0}
.actionwin-controls-col{flex:0 0 336px;min-width:0}
.oc-quickstats{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px}
.stat-chip{background:var(--panel);border:1px solid var(--rule);border-radius:5px;padding:5px 10px;font-size:11.5px;color:var(--ink2);font-weight:600;white-space:nowrap}
.stat-chip b{color:var(--ink);font-weight:800}
@media (max-width:760px){
  .actionwin-layout{flex-direction:column}
  .actionwin-controls-col{flex:0 0 auto;width:100%}
  .actionwin-map-wrap svg{max-height:38vh}
}
/* R82 bomb dial: a fixed N/E/S/W cue over the map so "bearing" reads as a
   real compass direction, not just a number — the map itself is always
   drawn north-up (matching the main board), this just makes that explicit. */
.compass-rose{position:absolute;top:8px;left:8px;width:40px;height:40px;pointer-events:none}
.route-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.oc-slider-label{font-size:11px;font-weight:800;letter-spacing:.04em;color:var(--ink2);margin-bottom:4px}
.oc-slider-sublabel{font-size:10.5px;color:var(--ink2);margin-top:3px;min-height:13px}
.oc-slider{width:100%;min-height:44px}
.oc-slider-banded{-webkit-appearance:none;appearance:none;background:transparent}
.oc-slider-banded::-webkit-slider-runnable-track{height:14px;border-radius:7px;background:var(--band-bg, var(--rule))}
.oc-slider-banded::-moz-range-track{height:14px;border-radius:7px;background:var(--band-bg, var(--rule))}
.oc-slider-banded::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:24px;height:24px;margin-top:-5px;border-radius:50%;background:#fff;border:2px solid var(--accent);box-shadow:0 1px 3px rgba(0,0,0,.35)}
.oc-slider-banded::-moz-range-thumb{width:24px;height:24px;border-radius:50%;background:#fff;border:2px solid var(--accent);box-shadow:0 1px 3px rgba(0,0,0,.35)}
.oc-number-field{width:90px;min-height:44px;margin-top:4px;padding:4px 8px;border:1px solid var(--rule);border-radius:4px;font-size:14px}
.waypoint-pin{width:24px !important;height:24px !important;font-size:10px !important}
/* R106: an armed robot's waypoint pins are buttons -- a 44px hit area around the 24px pin. */
.waypoint-pin.tappable{cursor:pointer}
.waypoint-pin.tappable::before{content:"";position:absolute;inset:-10px}
.waypoint-pin.armed{box-shadow:0 0 0 3px #FF4757}
#bombwin-svg.tap-aim{cursor:crosshair}
.oc-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}
.oc-head h3{font-size:14px}
.oc-section{margin-bottom:10px}
.oc-labels{display:flex;justify-content:space-between;font-size:10px;font-weight:800;letter-spacing:.04em}
.route-strip{position:relative;height:60px;background:var(--panel);border:1px solid var(--rule);border-radius:5px;margin:6px 0;touch-action:none}
.route-strip .line{position:absolute;top:29px;left:20px;right:20px;height:3px;background:repeating-linear-gradient(90deg,var(--accent) 0 6px, transparent 6px 10px)}
.route-strip .endpt{position:absolute;top:14px;width:30px;height:30px;border-radius:50%;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:800;font-size:11px;border:2px solid #fff}
/* R85: the destination is a DIAMOND, not another numbered circle — on the
   strip and on the map alike, so "where the journey ends" is a shape you
   can tell apart from a waypoint pin without reading a number or a color.
   The svg glyph supplies its own fill/stroke, so the div itself carries no
   background or border here. */
.route-strip .endpt.destination-pin{background:none;border:none}
.route-strip .tick{position:absolute;top:22px;width:1px;height:16px;background:#B0B6BF}
.route-strip .tick-lbl{position:absolute;top:40px;font-size:9px;color:var(--ink3);transform:translateX(-50%)}
/* Round 5 (Larry/Max): "the marker is the one precise gesture in the game"
   (rules.html §23), so its DRAG HIT AREA is 44x44 even though the visible
   dot stays 26px -- the outer element is the invisible target, centered on
   an inner dot that carries the actual look. */
.wf-marker{position:absolute;top:6px;width:44px;height:44px;transform:translate(-50%,0);cursor:grab;touch-action:none;display:flex;align-items:center;justify-content:center}
.wf-marker-dot{width:26px;height:26px;border-radius:50%;background:#FF4757;border:2px solid #fff;display:flex;align-items:center;justify-content:center;color:#fff;font-size:12px;font-weight:800;pointer-events:none}
/* R85: baseline placement only — distinct class for Iceberg's visual pass
   (make it read as its own kind of marker, not a waypoint or the
   weapons-free marker). transform centers it on its %-left position, same
   as the other strip markers. */
.mine-pin-marker{position:absolute;top:14px;width:30px;height:30px;border-radius:6px;background:var(--cap-mine);border:2px solid #fff;display:flex;align-items:center;justify-content:center;transform:translateX(-50%);pointer-events:none}
.wf-mode-btns{display:flex;gap:6px;margin-top:4px}
.wf-mode-btns button.active{background:var(--danger);color:#fff;border-color:var(--danger)}
.oc-cost-note{background:var(--panel);border:1px solid var(--rule);border-radius:5px;padding:8px 10px;font-size:11.5px;color:var(--ink2);margin-top:6px}
.target-opts{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}
.target-opts button.active{background:var(--accent);color:#fff;border-color:var(--accent)}
.oc-note{font-size:11px;color:var(--ink3);margin-top:4px}
.oc-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:10px}

/* overlays */
.overlay{position:fixed;inset:0;background:rgba(11,14,20,.72);z-index:100;display:flex;align-items:center;justify-content:center;padding:16px}
.overlay.hidden{display:none}
/* The action window hangs from the top instead of centering: its content changes
   height as taps add the weapons panel, a pin note, a refusal note -- and a
   centered panel would slide the map under the player's finger with each one. */
#overlay-actionwin{align-items:flex-start;padding-top:max(16px,4vh)}
/* Robot cards are role=button: show focus, and a hint where an order is wanted. */
.unit-card:focus-visible{outline:3px solid var(--accent);outline-offset:2px}
.unit-card.destroyed{cursor:default}
.cargo-tab{margin-right:6px}
.dup-notice{margin-top:4px;font-size:11px;font-weight:800;color:var(--warn-text);background:var(--warn-bg);border:1px solid var(--warn-border);border-radius:3px;padding:3px 8px}
.dup-notice + .btn{margin-top:4px}
.dup-section .btn.active{background:var(--accent);border-color:var(--accent);color:#fff}
.read-only .tap-hint,.read-only .card-actions,.read-only .dup-notice + .btn{display:none !important}
.read-only .unit-card{cursor:default}
.tap-hint{display:inline-block;margin-top:4px;font-size:10.5px;font-weight:800;color:var(--accent);background:#EAF4FB;border:1px dashed var(--accent);border-radius:3px;padding:2px 8px}
.overlay-panel{background:#fff;border-radius:8px;max-width:760px;width:100%;max-height:88vh;overflow-y:auto;padding:18px}
.overlay-panel h2{font-size:17px;margin-bottom:10px}
.overlay-panel-header{position:sticky;top:0;background:#fff;display:flex;justify-content:space-between;align-items:center;gap:10px;padding:14px 10px 14px 18px;border-bottom:1px solid var(--rule);z-index:2;border-radius:8px 8px 0 0}
.overlay-panel-header h2{margin:0;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Round 5 (Larry): the turn countdown, visible where the decision actually
   happens -- inside the action window -- since the clock keeps running
   while the window is open (rules.html §14: expiry submits standing
   orders). Same font/weight as the top bar's timer-btn, recolored for a
   light header; turns to the danger color under 30 seconds, same as the
   deadline note elsewhere uses var(--danger)/var(--danger-bg). */
.actionwin-timer{font-weight:800;font-size:13px;color:var(--ink);background:var(--panel);border:1px solid var(--rule);border-radius:4px;padding:6px 10px;flex:0 0 auto}
.actionwin-timer.danger{color:var(--danger);background:var(--danger-bg);border-color:var(--danger-border)}
.overlay-panel-body{padding:14px 18px 18px}
.overlay-close-btn{background:none;border:none;font-size:22px;line-height:1;min-height:44px;min-width:44px;color:var(--ink2);border-radius:4px;flex:0 0 auto}
.overlay-close-btn:hover{background:var(--panel)}

/* Round 5 (Vince/Larry, phone blocker 1): an overlay's own content (map +
   controls, or a long recap) can run taller than the panel at any size, not
   just on a phone. Rather than the whole panel scrolling as one unit --
   which leaves the primary action to scroll away below the fold -- the
   header stays a plain static bar, the BODY is the one thing that scrolls,
   and the action row (.oc-actions) is pinned to the bottom of that same
   scroll region so it's always reachable regardless of content length.
   .actionwin-panel is shared by #overlay-actionwin (robot orders, repair,
   reconfigure, bomb aim) and #overlay-end (the recap) -- both use the same
   sticky-header/scrolling-body/sticky-footer chrome. */
.actionwin-panel{display:flex;flex-direction:column;overflow:hidden}
.actionwin-panel .overlay-panel-header{position:static;flex:0 0 auto}
.actionwin-panel .overlay-panel-body{flex:1 1 auto;min-height:0;overflow-y:auto}
.actionwin-panel .oc-actions{position:sticky;bottom:0;background:#fff;margin:10px -18px -18px;padding:10px 18px;box-shadow:0 -4px 8px rgba(0,0,0,.06)}
.menu-list button{display:block;width:100%;text-align:left;padding:12px 14px;margin-bottom:8px;font-size:14px}
.confirm-box{background:var(--danger-bg);border:1px solid var(--danger-border);border-radius:6px;padding:12px;margin:10px 0;font-size:13px}

/* replay */
#replay-map-wrap{background:var(--board-bg);border-radius:6px;overflow:hidden;margin-bottom:10px}
.replay-controls{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px}
.replay-controls input[type=range]{flex:1;min-width:120px;min-height:44px}
.speed-btn.active{background:var(--accent);color:#fff;border-color:var(--accent)}
#replay-summary{font-size:13px;margin-bottom:8px;background:var(--panel);border-radius:5px;padding:8px 10px}
#replay-log{max-height:160px;overflow-y:auto;border:1px solid var(--rule);border-radius:5px}
.replay-log-item{padding:6px 10px;font-size:12px;border-bottom:1px solid var(--rule);cursor:pointer}
.replay-log-item:last-child{border-bottom:none}
.replay-log-item.current{background:#EAF4FB}

/* end screen */
.end-banner{font-size:22px;font-weight:800;margin-bottom:8px}
.assumption-list{font-size:11.5px;color:var(--ink2)}

/* seat banner */
#ai-seat-banner{position:fixed;top:0;left:0;right:0;background:#7A5A0F;color:#fff;padding:8px 14px;display:flex;justify-content:space-between;align-items:center;z-index:60;font-size:13px;font-weight:700}
#ai-seat-banner.hidden{display:none}
#ai-seat-banner button{background:#fff;color:#7A5A0F;border:none;border-radius:4px;padding:6px 12px;font-weight:800}

/* toast */
#toast{position:fixed;bottom:80px;left:50%;transform:translateX(-50%);background:var(--ink);color:#fff;padding:8px 16px;border-radius:20px;font-size:12.5px;z-index:200;box-shadow:0 4px 12px rgba(0,0,0,.3)}
#toast.hidden{display:none}

/* ================= responsive: phone ================= */
@media (max-width:480px){
  .cfg-body{grid-template-columns:1fr;gap:10px}
  .cfg-palette{position:sticky;top:0;z-index:5;display:flex;flex-wrap:wrap;gap:4px;padding:8px}
  .cfg-palette h4{width:100%}
  .cap-chip{flex:1 1 44%;margin-bottom:0;flex-wrap:wrap;row-gap:2px}
  .cap-chip .short{flex:1 0 100%;text-align:left;opacity:.85}
  .cfg-guidance{order:3}
  .cfg-rows{order:2}
  .cfg-rows .robot-row{display:none}
  .cfg-rows .robot-row.cfg-active{display:block}
  #cfg-mobile-pager{display:flex;gap:6px;justify-content:center;margin:8px 0}
  #cfg-mobile-pager button{min-width:44px}
  #cfg-mobile-pager button.active{background:var(--accent);color:#fff;border-color:var(--accent)}
  .cfg-header{position:sticky;top:0;z-index:6}

  #screen-board{grid-template-columns:1fr;grid-template-rows:auto 1fr auto auto auto;height:100vh}
  /* Round 5 (Vince/Larry): a grid track's automatic minimum size won't
     shrink below a child's min-content — a flex row with flex:1 children
     computes that as its un-wrapped preferred width, ignoring flex-wrap, so
     the single 1fr column below was blowing out to ~416px on a 375px phone
     and forcing the whole page to scroll horizontally. min-width:0 on every
     direct grid item here removes that floor; each item's own children
     still wrap/scroll exactly as their own CSS already says. */
  #screen-board > *{min-width:0}
  .squad-sheet-handle{
    display:flex;align-items:center;justify-content:center;gap:6px;grid-column:1;
    min-height:44px;background:var(--panel);border-top:1px solid var(--rule);
    font-size:12px;font-weight:800;color:var(--ink2);letter-spacing:.04em;
  }
  .squad-panel{
    grid-column:1;max-height:40vh;border-left:none;border-top:1px solid var(--rule);
    flex-direction:row;overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;
    box-shadow:0 -4px 10px rgba(0,0,0,.12);transition:max-height .18s ease,padding .18s ease;
  }
  .squad-panel.collapsed{max-height:0;padding-top:0;padding-bottom:0;border-top:none;box-shadow:none;overflow:hidden}
  .unit-card,.base-card,.repair-card{min-width:78vw;scroll-snap-align:start}
  .bottombar{grid-column:1}
  .topbar{grid-column:1}
  .map-wrap{grid-column:1;min-height:0}
  /* R99 is public progress for ALL FOUR players: on a phone the tracker takes a
     full row of its own as a 2x2 grid instead of a clipped scroller. */
  .topbar{row-gap:4px}
  .delivered-tracker{order:10;flex:1 1 100%;display:grid;grid-template-columns:1fr 1fr;gap:2px 8px;overflow:visible}
  .delivered-row{flex-wrap:wrap;row-gap:0}
  /* R82 §23: the action window is full-screen on a phone. Prefer the
     dynamic viewport height (100dvh) so a phone browser's own chrome
     (address bar showing/hiding) doesn't leave content hidden behind it;
     100vh is the fallback for browsers that don't know dvh. Never size this
     from window.innerWidth/innerHeight in script -- CSS units only. */
  #overlay-actionwin{padding:0}
  #overlay-actionwin .actionwin-panel{
    position:fixed; inset:0; max-width:none; width:auto; max-height:none; border-radius:0;
    height:100vh; height:100dvh;
  }
}
