/* HUD — minimal, documentary. Reticle states carry the ROE/PID language. */
#hud { position: absolute; inset: 0; pointer-events: none; }

.hud-bl { position: absolute; left: 18px; bottom: 16px; }
.hp-wrap { width: 180px; height: 10px; border: 1px solid rgba(232,224,204,.55); background: rgba(0,0,0,.35); position: relative; }
.hp-fill { height: 100%; width: 100%; background: var(--paper-dim); transition: width .15s; }
.hp-fill.bleeding { background: var(--hostile-red); animation: bleedpulse 1s infinite; }
@keyframes bleedpulse { 50% { opacity: .55; } }
.hp-label { position: absolute; right: -34px; top: -4px; font-size: 12px; }
.hud-row { margin-top: 6px; font-size: 14px; letter-spacing: .08em; display: flex; gap: 14px; }
.bandages { color: var(--sand); }

/* One objective row plus one reserved condition/escort row. The escort span
   stays in the objective's semantic line while sharing the second visual row. */
.mission-readout { position: absolute; top: 14px; left: 18px; right: 238px;
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 12px;
  max-width: 760px; padding: 5px 10px; box-sizing: border-box;
  color: var(--paper); background: rgba(var(--base-rgb),.72); z-index: 3;
  /* the accent rule marks this as THE objective line — chrome, not a person */
  border-left: 2px solid var(--accent);
  font-size: 12px; line-height: 18px; }
.mission-readout .objective { display: contents; text-transform: uppercase; }
.objective-text { grid-column: 1 / -1; grid-row: 1; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.mission-readout:has(.timer:not([style*="none"])) .objective-text { padding-right: 64px; }
.escort-status { grid-column: 2; grid-row: 2; white-space: nowrap; color: var(--sand); }
.condition-row { display: contents; }
.theatre-condition { grid-column: 1; grid-row: 2; white-space: nowrap; }
.mission-readout .timer { justify-self: end; position: static; transform: none; grid-column: 2; grid-row: 1;
  padding: 0; font-size: 12px; line-height: 18px; background: none; }
body.touch-ui .mission-readout { left: calc(10px + env(safe-area-inset-left, 0px));
  right: calc(132px + env(safe-area-inset-right, 0px)); top: calc(10px + env(safe-area-inset-top, 0px)); }
/* Portrait uses the full width just below the map/tutorial strip. This keeps
   both labels readable without shrinking type or covering an action target. */
@media (max-width: 600px) {
  body.touch-ui .mission-readout { top: calc(140px + env(safe-area-inset-top, 0px));
    right: calc(10px + env(safe-area-inset-right, 0px)); gap: 2px 8px; padding: 4px 8px; }
}

.channel { position: absolute; left: 50%; bottom: 26%; transform: translateX(-50%);
  width: 120px; height: 6px; border: 1px solid rgba(232,224,204,.5); display: none; }
.channel-fill { height: 100%; background: var(--accent); }

.reticle { position: absolute; width: 0; height: 0; --pid: 0; }
.ret-dot { position: absolute; left: -2px; top: -2px; width: 4px; height: 4px; background: #fff; border-radius: 50%; }
.ret-ring { position: absolute; left: -13px; top: -13px; width: 26px; height: 26px; border-radius: 50%;
  border: 1.5px solid rgba(255,255,255,.85);
  background: conic-gradient(rgba(255,255,255,.35) calc(var(--pid) * 360deg), transparent 0); }
.ret-chip { position: absolute; left: 16px; top: -8px; font-size: 10px; letter-spacing: .12em; white-space: nowrap; }

/* Identification states — the pid tokens (theme.js), NEVER --accent. The UI
   amber is chrome; if it ever marked a person it would be a second, unearned
   PID channel. `unknown` stays the darker #b5822e so it cannot read as chrome. */
.reticle[data-state="hostile"] .ret-ring { border-color: var(--hostile-red); }
.reticle[data-state="hostile"] .ret-dot { background: var(--hostile-red); }
.reticle[data-state="civilian"] .ret-ring { border-color: var(--civilian-blue); }
.reticle[data-state="civilian"] .ret-dot { background: var(--civilian-blue); }
.reticle[data-state="unknown"] .ret-ring { border-color: var(--warn-amber); }
.reticle[data-state="protected"] .ret-ring { border-color: #fff; box-shadow: 0 0 0 3px rgba(255,255,255,.25); }
.reticle[data-state="protected"] .ret-chip { color: #fff; font-weight: bold; }

.pickup-toast {
  position: absolute; left: 50%; bottom: 24%; transform: translateX(-50%) translateY(6px);
  font-size: 14px; letter-spacing: .14em; color: var(--sand);
  background: rgba(var(--base-rgb),.72); border: 1px solid rgba(var(--accent-rgb),.45);
  padding: 4px 14px; opacity: 0; pointer-events: none;
  transition: opacity .18s, transform .18s;
}
.pickup-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
body.touch-ui .pickup-toast { bottom: 34%; }

/* ROE VIOLATION NOTICE
 *
 * Deliberately NOT the pickup toast. A violation is the one thing this game is
 * about, and until now it was silent in play — the player learned at the
 * debrief that they had shot someone they never identified, by which point they
 * could no longer connect it to the moment or change what they did next. A
 * conduct system that only speaks after the run is a scoreboard, not a rule.
 *
 * Top band, not bottom: the bottom is dialogue, prompts and the pickup toast,
 * and this must never be one of four things stacked in the same strip (#78 was
 * exactly that failure). It sits clear of the objective line at the top-left.
 *
 * The tone is a log entry, not a buzzer. Ink on a dark ground with a red rule,
 * stating what happened and what it cost — no flash, no shake, no scolding.
 * The game's position is that the player is an adult being told the record. */
.roe-alert {
  position: absolute; left: 50%; top: 12%; transform: translateX(-50%) translateY(-6px);
  max-width: 78%; text-align: center;
  font-size: 13px; letter-spacing: .16em; line-height: 1.5;
  color: #f0d9c4; background: rgba(28,12,10,.86);
  border: 1px solid rgba(194,58,40,.75); border-left: 3px solid #c23a28;
  padding: 6px 16px; opacity: 0; pointer-events: none;
  transition: opacity .16s, transform .16s;
}
.roe-alert.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.roe-alert .roe-cost { display: block; font-size: 11px; letter-spacing: .12em; opacity: .78; }
body.touch-ui .roe-alert { top: max(16%, 64px); font-size: 12px; }
@media (max-width: 600px) { body.touch-ui .roe-alert { top: calc(196px + env(safe-area-inset-top, 0px)); } }

/* An interactable prompt: amber legend and rule. The ground is .72, not .65 —
   .72 is the thinnest panel on which accent TEXT still clears 4.5:1 over the
   brightest sand in the grade (theme.js). */
.prompt { position: absolute; left: 50%; bottom: 32%; transform: translateX(-50%);
  font-size: 14px; letter-spacing: .14em; color: var(--accent);
  background: rgba(var(--base-rgb),.72); padding: 4px 14px; border: 1px solid rgba(var(--accent-rgb),.55); }

.ied-vignette { position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(ellipse at center, transparent 46%, rgba(160,51,40,.55) 100%);
  transition: opacity .25s; }

/* fault toast + context-loss overlay */
.fault-toast { position: absolute; top: 70px; left: 50%; transform: translateX(-50%);
  background: rgba(141,47,35,.9); color: #f0e8d8; font-size: 12px; letter-spacing: .12em;
  padding: 6px 16px; opacity: 0; transition: opacity .3s; pointer-events: none; }
.fault-toast.show { opacity: 1; }
.screen.glloss { background: rgba(15,13,9,.94); z-index: 60; }

/* touch layer */
#touch { position: absolute; inset: 0; pointer-events: none; }
.stick-zone { position: absolute; bottom: 0; width: 46%; height: 46%; pointer-events: auto; }
.stick-zone.left { left: 0; }
.stick-zone.right { right: 0; }
.view-fade { position: fixed; inset: 0; background: #000; opacity: 0; pointer-events: none; z-index: 12; }
.desktop-view { position: absolute; right: 12px; bottom: 18px; min-height: 44px; pointer-events: auto; font-size: 12px; }
.view-hint { position: absolute; left: 50%; bottom: 74px; transform: translateX(-50%); max-width: 65%;
  font-size: 11px; color: var(--sand); text-align: center; background: rgba(15,13,9,.75); }
.view-hint:empty { display: none; }
.touch-ui .desktop-view { display: none; }
.eye-look { display: none; position: absolute; right: 76px; width: calc(50% - 76px); bottom: 0; height: 40%;
  pointer-events: auto; touch-action: none; }
.eye-fire { display: none; position: absolute; right: 12px; bottom: 75px; width: 56px; height: 56px;
  pointer-events: auto; touch-action: none; }
#touch.eye-view .eye-look { display: block; }
#touch.eye-view .eye-fire { display: flex; }
.view-button { font-size: 9px; }
#touch .view-button { width: 106px; border-radius: 8px; padding: 4px; }
#touch:not(.eye-view) .view-button { position: fixed; left: 50%; bottom: 12px; transform: translateX(-50%); }
#touch.eye-view .touch-buttons { display: grid; grid-template-columns: repeat(3, 48px); gap: 8px; bottom: 164px; }
#touch.eye-view .view-button { width: 160px; grid-column: 1 / -1; }
.touch-ui #hud.eye-view .view-hint { bottom: 140px; max-width: 75%; font-size: 10px; }
#hud.eye-view .scope-overlay, #hud.eye-view .scope-edge { transition: none; }
@media (orientation: landscape) and (max-height: 500px) {
  #touch.eye-view .touch-buttons { bottom: 12px; right: 84px; grid-template-columns: repeat(4, 48px); }
  #touch.eye-view .view-button { width: 216px; }
  .eye-look { right: 0; width: 48%; bottom: 180px; height: calc(100% - 210px); }
  .touch-ui #hud.eye-view .view-hint { bottom: 164px; }
}
/* Anchored from the BOTTOM, not the top: the old `top: 40%` let a tall stack
   of always-on buttons grow downward straight into the right stick's zone
   (bottom-anchored, 46% of the screen) — exactly the congestion players hit.
   Pinning the group's bottom edge just above the stick's ~19vh visual reach
   (see the touch-clearance comment in screens.css) means the column grows
   UP, away from the aiming thumb, and the last child (FIRE) lands lowest —
   closest to that clearance line — without ever overlapping the stick. Most
   buttons are also now conditionally hidden (src/ui/touch.js) so the column
   rarely stacks this tall in practice. */
.touch-buttons {
  position: absolute; right: calc(10px + env(safe-area-inset-right, 0px));
  bottom: calc(19vh + 14px);
  display: flex; flex-direction: column; align-items: flex-end; gap: 10px; pointer-events: auto;
}
.tbtn { width: 48px; height: 48px; min-width: 0; padding: 0; font-size: 10px; letter-spacing: .06em;
  border-radius: 50%; border: 1.5px solid rgba(232,224,204,.55);
  background: radial-gradient(circle at 35% 30%, rgba(120,112,96,.55), rgba(38,33,25,.72));
  box-shadow: inset 0 1px 0 rgba(255,250,235,.18), inset 0 -3px 8px rgba(0,0,0,.45), 0 3px 10px rgba(0,0,0,.4);
  color: var(--sand); text-shadow: 0 1px 2px rgba(0,0,0,.8);
  display: flex; align-items: center; justify-content: center;
  transition: transform .08s, opacity .15s;
  font-family: var(--type); }
.tbtn:active { transform: scale(.92); background: radial-gradient(circle at 35% 30%, rgba(150,140,120,.6), rgba(50,44,34,.8)); }
/* de-emphasised, not hidden — e.g. reload with a full mag: still one tap
   away (moving cancels nothing pending), just not competing for attention */
.tbtn.dim { opacity: .45; }

/* ---- the ONE weapon control (#73) -----------------------------------------
   This replaces the old dedicated FIRE button as the largest circle in the
   column: fire moved into the aim stick (#74), and what used to be three
   competing controls (KNIFE / WPN / FRAG's weapon half) is now the one thing
   here that matters enough to earn the emphasis FIRE used to have. Warm tone
   kept for the same reason: it is still the control the thumb finds first. */
.tbtn.tbtn-weapon {
  width: 58px; height: 58px;
  border-color: rgba(var(--accent-rgb),.6);   /* was a red-orange: red is hostile-only */
  background: radial-gradient(circle at 35% 30%, rgba(130,90,60,.55), rgba(42,28,20,.75));
}
.tbtn.tbtn-weapon:active { background: radial-gradient(circle at 35% 30%, rgba(170,110,70,.65), rgba(56,34,22,.82)); }
.tbtn-weapon img {
  width: 74%; height: 74%; object-fit: contain; pointer-events: none;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.8));
}
/* Shown only when a weapon has no generated icon yet (see touch.js's
   WEAPON_ICON) — same idea as hud.js's text fallback for an un-keyed weapon
   name, just for a button instead of a HUD line. */
.tbtn-weapon-fallback { display: none; font-size: 9px; letter-spacing: .05em; }

/* ---- tutorial ------------------------------------------------------------
   Sits ABOVE the two touch sticks with clearance, never over them: a prompt
   that overlaps a control is worse than no prompt, because the player taps it
   trying to move. Never modal, never blocking — pointer-events stay off except
   on the skip button itself. */
#tutorial {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: 20%;
  display: flex; align-items: center; gap: 10px;
  /* Explicit width, not max-width: an absolutely positioned element at
     left:50% shrink-wraps to the REMAINING half of the container, so on a
     390px phone it came out 195px wide and the line wrapped four deep. */
  width: min(92vw, 560px);
  box-sizing: border-box;
  padding: 9px 14px;
  /* A COMMS DEVICE, not a piece of ops-room furniture. This deliberately does
     NOT share the steel-plate material used by the mission cards and menu:
     that is welded equipment, this is a moulded field-radio faceplate — dark
     olive-charcoal polymer, smooth, with a soft top sheen instead of brushed
     metal grain. Sharing one material across both made the whole UI read as a
     single sheet of the same stuff.
     The green belongs to the TEXT, and the text sits in a RECESSED display
     window — the inner dark inset below is the sunken screen the phosphor
     lives behind, which is what gives the panel depth without a green frame. */
  background-color: #2b2f2b;
  background-image:
    linear-gradient(rgba(255, 255, 245, 0.07) 0%, rgba(255, 255, 245, 0.02) 42%, rgba(0, 0, 0, 0.28) 100%);
  border: 1px solid #14170f;
  border-top-color: rgba(228, 236, 220, 0.16);
  border-radius: 7px;                    /* moulded, not cut */
  box-shadow:
    inset 0 1px 0 rgba(236, 244, 228, 0.14),   /* moulding highlight */
    inset 0 0 0 1px rgba(0, 0, 0, 0.35),        /* the recessed screen bezel */
    inset 0 3px 12px rgba(0, 0, 0, 0.55),       /* screen sunk into the shell */
    0 5px 16px rgba(0, 0, 0, 0.5);
  color: var(--term-green, #7dfa9a);
  text-shadow: 0 0 6px rgba(125, 250, 154, 0.30);
  font-family: var(--type); font-size: 14px; line-height: 1.35;
  opacity: 0; pointer-events: none;
  transition: opacity .25s ease;
  z-index: 6;
}
#tutorial.show { opacity: 1; }
/* A decision outranks an advisory prompt. Both are bottom-anchored and they
   collided — the third option sat behind this panel, unclickable. */
body.choosing #tutorial { opacity: 0 !important; pointer-events: none; }
.tut-line { flex: 1; }
/* ---- THE GAMEPLAY KEYCAP -------------------------------------------------
   The house style for every button that interrupts play: the tutorial's SKIP,
   and — the important one — the dialogue CHOICE buttons, which is where the
   negotiation and every future branching decision is taken.
   Those choices deserve to feel like a committed act rather than a web link,
   and a struck key is exactly that. Menus and briefings keep their own
   materials (steel plate and ink-on-paper); this is specifically the in-world,
   mid-mission register. */
.keycap, .tut-skip, #dialogue .choices button {
  pointer-events: auto;
  /* A TYPEWRITER KEY. Not a comms legend — the green belongs to the message,
     and a green button made the whole panel one undifferentiated glow. This is
     a black keycap with a WHITE legend, which is what every machine of this
     era actually used and what makes it read as a separate physical object
     sitting on the device.
     Three things do the work: a DISHED face (the radial gradient is darker in
     the centre, because a key you press a thousand times is concave), a metal
     COLLAR around the cap (the pale ring), and a real bevel — lit along the top
     lip, black along the bottom. */
  background-color: #0e0e10;
  background-image:
    radial-gradient(115% 130% at 50% 6%, rgba(255, 255, 255, 0.20) 0%, rgba(255, 255, 255, 0.05) 34%, rgba(0, 0, 0, 0.34) 74%, rgba(0, 0, 0, 0.52) 100%);
  border: 1px solid #000;
  border-radius: 5px;
  box-shadow:
    inset 0 1.5px 0 rgba(255, 255, 255, 0.34),   /* lit top lip of the cap */
    inset 0 -2px 3px rgba(0, 0, 0, 0.85),         /* dished shadow at the base */
    0 0 0 1.5px #9a958a,                          /* the metal collar */
    0 0 0 2.5px rgba(0, 0, 0, 0.55),
    0 2.5px 0 #4a4640,                            /* the key's own side wall */
    0 4px 6px rgba(0, 0, 0, 0.6);
  color: #f4f1ea;                                 /* white legend, not phosphor */
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.9);
  font-family: var(--type); font-size: 11px; letter-spacing: .16em;
  padding: 4px 10px; cursor: pointer; flex: none;
  min-width: 44px; min-height: 32px;  /* stays tappable on a phone */
  transition: filter .12s, transform .05s, box-shadow .05s;
}
/* ROUND CAP — the true typewriter form, and it only works for a SHORT legend.
   A circle sets its own width from its height, so a sentence cannot live in
   one; the choice buttons below stay rectangular for exactly that reason.
   The collar reads even better on a circle than on a rounded square, because
   a ring is what a real typewriter key actually has. */
.keycap.round, .tut-skip {
  border-radius: 50%;
  width: 46px; height: 46px;
  min-width: 46px; min-height: 46px;
  padding: 0;
  font-size: 9.5px; letter-spacing: .1em;
  display: flex; align-items: center; justify-content: center;
}

/* A choice is a SENTENCE, not a legend: wider padding, sentence spacing, and
   left-aligned so a stack of three reads as a list of things you could do
   rather than three identical chips. */
#dialogue .choices button {
  margin: 5px 0;
  padding: 10px 16px;
  font-size: 13px;
  letter-spacing: .04em;
  text-align: left;
  text-transform: none;
  max-width: min(86vw, 560px);
}
.keycap:hover, .tut-skip:hover, #dialogue .choices button:hover,
.keycap:focus-visible, .tut-skip:focus-visible, #dialogue .choices button:focus-visible { outline: none; filter: brightness(1.25); }
/* Struck: the cap travels down onto its own side wall, which collapses to
   nothing — that vertical drop is what a key press actually looks like. */
.keycap:active, .tut-skip:active, #dialogue .choices button:active {
  transform: translateY(2.5px);
  box-shadow:
    inset 0 2px 4px rgba(0, 0, 0, 0.9),
    0 0 0 1.5px #9a958a,
    0 0 0 2.5px rgba(0, 0, 0, 0.55),
    0 0 0 #4a4640,
    0 1px 2px rgba(0, 0, 0, 0.6);
}

/* On touch the whole lower half is spoken for: two sticks across the bottom, a
   column of action buttons up the right side, and the dialogue line in the
   middle. Anchored low it landed on top of all three. The empty band is the top
   strip beside the minimap, so it goes there — always visible, never over a
   control, and matching the rule that alerts clear the control circles. */
body.touch-ui #tutorial {
  top: calc(12px + env(safe-area-inset-top, 0px));
  bottom: auto;
  left: calc(10px + env(safe-area-inset-left, 0px));
  right: 132px;                 /* clears the minimap in the top-right corner */
  width: auto; transform: none;
  font-size: 13px;
}

@media (prefers-reduced-motion: reduce) { #tutorial { transition: none; } }

@media (min-width: 601px) {
  body.touch-ui #tutorial { top: calc(64px + env(safe-area-inset-top, 0px));
    max-width: min(380px, calc(50vw - 24px)); }
  body.touch-ui:has(#tutorial.show) .roe-alert { top: calc(150px + env(safe-area-inset-top, 0px)); }
}

/* First-use mode tips (modeTips.js): optic, night vision, channels. They sit in
   the tutorial's slot, which they never share (the tutorial outranks them), and
   only the OK key takes a pointer — the box can never swallow an aim or a shot.
   Hidden, not dismissed, while a toast holds the same band. */
.mode-tip { position: absolute; left: 50%; bottom: 20%; transform: translateX(-50%);
  width: min(92vw, 560px); box-sizing: border-box; display: flex; align-items: center; gap: 10px;
  padding: 6px 8px 6px 12px; font-size: 13px; line-height: 18px; color: var(--paper);
  background: rgba(var(--base-rgb),.8); border: 1px solid rgba(var(--accent-rgb),.45); pointer-events: none; z-index: 6; }
.mode-tip[hidden] { display: none; }
.mode-tip-line { flex: 1; }
.mode-tip-ok { flex: none; }
#hud:has(.pickup-toast.show) .mode-tip { visibility: hidden; }
body.touch-ui .mode-tip { top: calc(12px + env(safe-area-inset-top, 0px)); bottom: auto;
  left: calc(10px + env(safe-area-inset-left, 0px)); right: 132px; width: auto; transform: none;
  font-size: 12px; line-height: 16px; }
@media (min-width: 601px) {
  body.touch-ui .mode-tip { top: calc(64px + env(safe-area-inset-top, 0px));
    max-width: min(380px, calc(50vw - 24px)); }
  body.touch-ui:has(.mode-tip:not([hidden])) .roe-alert { top: calc(150px + env(safe-area-inset-top, 0px)); }
}

/* Driving leaves the road corridor clear; readouts use the existing lower
   status strip and the one first-entry hint ends on an actual exit. */
.drive-readout { margin-bottom: 8px; color: var(--paper); font-size: 12px; line-height: 18px;
  font-variant-numeric: tabular-nums; text-shadow: 0 1px 3px #000; }
.drive-hint { position: absolute; top: 57%; left: 25%; right: 25%; padding: 6px 10px;
  font-size: 12px; line-height: 17px; color: var(--paper); background: rgba(var(--base-rgb),.72); }
#hud.riding .roe-alert { top: 57%; }
#hud.riding .prompt { top: 76%; bottom: auto; width: max-content; max-width: 66%; text-align: center; }
body:has(#hud.riding) #dialogue .subtitle { top: 57%; bottom: auto; width: 74vw; }
#hud.riding:has(.roe-alert.show) .drive-hint { visibility: hidden; }
@media (max-width: 600px) {
  body.touch-ui #hud.riding .mission-readout { top: calc(130px + env(safe-area-inset-top, 0px));
    padding: 0 8px; line-height: 16px; }
  body.touch-ui:has(#hud.riding) #dialogue .subtitle { width: 66vw; }
  .drive-hint { left: 10px; right: 10px; }
}
@media (max-height: 500px) {
  .drive-hint { top: 57%; left: 25%; right: 25%; font-size: 11px; line-height: 15px; }
}
