/* ═══════════════════════════════════════════════════════════════════════
   TRUMP WARS · HOMELAND DEFENSE — core sheet ("Fleet Command Console", package U1)
   Tokens, base, primitives, panel recipe, status strip (#top), system row (#sys), comms log (#log).
   Later packages add css/ui-bar.css (U2), css/ui-intel.css (U3), css/ui-screens.css (U4).
   css/ui-legacy.css holds the pre-redesign rules for panels not ported yet; each package deletes its part.
   Units: 1rem = 10px at 1280x720 and scales with the viewport (20px at 2560x1440); never below 9px.
   Text floor: any font-size under 1rem is written max(9px, Xrem), so nothing state-bearing renders under 9px
   on a 1366x657 laptop viewport (rem 9.13px) or smaller.
   Fonts: Barlow Condensed (names, copy, primary numbers) + Share Tech Mono (secondary numbers, labels, keys,
   canvas text), loaded from node_modules/@fontsource via <link> in index.html. Glyphs outside those fonts
   (◆ ▸ ✕ ∞ ★) are drawn as CSS/SVG shapes, never typed.
   ═══════════════════════════════════════════════════════════════════════ */

/* ═══ U1 · TOKENS ═════════════════════════════════════════════════════════ */
:root {
  /* surfaces: neutral blue-black glass, never warm/olive over the blue city */
  --k0: #040507;
  --fill-a: rgba(12, 16, 22, .92);
  --fill-b: rgba(5, 8, 12, .9);
  --fill-solid: #0a0e14;
  --plate: rgba(5, 8, 12, .86);     /* backing for text that sits over the scene */
  /* linework (amber) */
  --amb: #ffb830;
  --ln: rgba(255, 184, 48, .5);
  --ln-2: rgba(255, 184, 48, .24);
  --ln-3: rgba(255, 184, 48, .11);
  /* brand: yellow = ours */
  --yel: #ffe81f;
  --yel-d: #c9b40f;
  /* text (warm white on cool glass) */
  --txt: #f4f0e2;
  --txt-2: #cdc6ab;
  --txt-3: #8e8a7a;
  /* allegiance: colour = side, shape = domain */
  --hos: #ff3b30;      /* hostile ground: pure red, never orange */
  --hos-air: #ff5fd2;  /* hostile air */
  --fr: #52d8ff;       /* friendly holo DATA (bars, values, rings), never a panel frame */
  --gnd: #ff9b45;      /* GND capability = the in-world ground-route chevron hue */
  --air: #6fd6ff;      /* AIR capability = the air-route chevron hue */
  --ok: #8dff8a;
  --warn: #ff9a1f;
  /* type */
  --f-txt: 'Barlow Condensed', 'Arial Narrow', sans-serif;
  --f-num: 'Share Tech Mono', ui-monospace, Consolas, monospace;
  --t-micro: max(9px, .9rem);   /* smallest state-bearing text */
  --t-tag: max(9px, .98rem);
  /* geometry */
  --cut: .9rem;
  --gap: 1.2rem;        /* screen-edge gutter */
}

html { font-size: clamp(9px, min(1.389vh, .781vw), 24px); }
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; height: 100%; overflow: hidden; background: var(--k0); color: var(--txt); font-family: var(--f-txt); font-weight: 500; -webkit-font-smoothing: antialiased; user-select: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; white-space: nowrap; }
button:focus { outline: none; }
button:focus-visible { outline: 1px dashed var(--yel); outline-offset: -3px; }
.mono { font-family: var(--f-num); font-weight: 400; }
.hidden { display: none !important; }
.nb { white-space: nowrap; }
/* credit mark: a drawn diamond, same everywhere (shop, tooltips, upgrade, sell, end card); never '¤' */
.cu { display: inline-block; width: .5em; height: .5em; margin: 0 .28em 0 .08em; border: max(1.5px, .09em) solid currentColor; transform: rotate(45deg) translateY(-.06em); vertical-align: .08em; }
/* drawn diamond marker (boss waves, Capitol); the ◆ glyph is not in either font */
.dia { display: inline-block; width: .55em; height: .55em; background: currentColor; transform: rotate(45deg); vertical-align: .08em; margin: 0 .3em 0 .1em; }

/* scene canvases */
#gl, #ov { position: fixed; inset: 0; width: 100%; height: 100%; display: block; }
#gl { cursor: none; }
#ov { pointer-events: none; z-index: 1; }
#flash { position: fixed; inset: 0; z-index: 3; background: #fff; opacity: 0; pointer-events: none; transition: opacity 1.4s ease-out; }

/* ── HUD root: never eats clicks; only real controls and solid panels opt in ─────────── */
#hud { position: fixed; inset: 0; z-index: 2; pointer-events: none; }
#hud button, #hud label, #hud .hit, #hud canvas.hit, #hud .cc { pointer-events: auto; }
/* text overlays stay click-through, so the battlefield under them can still be shot or built on */
#hud #log, #hud #help, #hud #banner, #hud #boss, #hud .tip-card { pointer-events: none; }

/* motion: only opacity/transform animate; ?still or reduced motion turns it off */
html.still #hud *, html.still #hud *::before, html.still #hud *::after { animation: none !important; transition: none !important; }
@media (prefers-reduced-motion: reduce) { #hud *, #hud *::before, #hud *::after { animation: none !important; transition: none !important; } }

/* ═══ U1 · PANEL RECIPE ════════════════════════════════════════════════════
   .cc  = chamfered console panel: amber hairline border, blue-black glass,
          top highlight, faint scanlines, bright amber ticks on the square corners.
   The element itself is NOT clipped (children, tooltips, caption tabs and
   focus rings may overflow). ::before = border layer (amber, clipped to the
   chamfer, carries the 2px corner ticks); ::after = fill layer inset 1px.
   No backdrop-filter anywhere: the glass is .9 alpha, which reads the same. */
.cc { position: relative; isolation: isolate; padding: 1rem 1.1rem;
  --poly: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  --tk: linear-gradient(var(--amb), var(--amb));
  --ticks: var(--tk) right top / 1.1rem 2px no-repeat, var(--tk) right top / 2px 1.1rem no-repeat, var(--tk) left bottom / 1.1rem 2px no-repeat, var(--tk) left bottom / 2px 1.1rem no-repeat;
  --ticks-in: var(--tk) right top / 1rem 1px no-repeat, var(--tk) right top / 1px 1rem no-repeat, var(--tk) left bottom / 1rem 1px no-repeat, var(--tk) left bottom / 1px 1rem no-repeat; }
.cc::before, .cc::after { content: ''; position: absolute; z-index: -1; pointer-events: none; clip-path: var(--poly); }
.cc::before { inset: 0; background: var(--ticks), var(--ln); }
.cc::after { inset: 1px;
  background: var(--ticks-in),
    linear-gradient(180deg, rgba(255, 214, 140, .07), rgba(255, 214, 140, 0) 1.6rem),
    repeating-linear-gradient(0deg, rgba(190, 220, 255, .025) 0 1px, transparent 1px 3px),
    linear-gradient(180deg, var(--fill-a), var(--fill-b)); }
.cc.quiet { --ticks: linear-gradient(transparent, transparent); --ticks-in: linear-gradient(transparent, transparent); }
/* reversed chamfer (top-right + bottom-left) for right-hand panels */
.cc.rev { --poly: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, var(--cut) 100%, 0 calc(100% - var(--cut)));
  --ticks: var(--tk) left top / 1.1rem 2px no-repeat, var(--tk) left top / 2px 1.1rem no-repeat, var(--tk) right bottom / 1.1rem 2px no-repeat, var(--tk) right bottom / 2px 1.1rem no-repeat;
  --ticks-in: var(--tk) left top / 1rem 1px no-repeat, var(--tk) left top / 1px 1rem no-repeat, var(--tk) right bottom / 1rem 1px no-repeat, var(--tk) right bottom / 1px 1rem no-repeat; }

/* ═══ U1 · PRIMITIVES ══════════════════════════════════════════════════════ */
/* micro-label header with trailing rule:  TACTICAL ───────── TWIN FRONTS */
.hd { display: flex; align-items: center; gap: .7rem; font: 400 1.05rem/1 var(--f-num); letter-spacing: .18em; text-transform: uppercase; color: var(--amb); white-space: nowrap; }
.hd::after { content: ''; flex: 1; height: 1px; background: linear-gradient(90deg, var(--ln), var(--ln-3)); order: 1; }
.hd > .r { order: 2; color: var(--txt-2); letter-spacing: .12em; }
.hd > .r b { color: var(--txt); font-weight: 400; }

/* label / value pairs */
.lbl { font: 400 1.05rem/1 var(--f-num); letter-spacing: .16em; text-transform: uppercase; color: var(--txt-2); }
/* primary numbers: heavy condensed, tabular, so they punch over bloom; secondary numbers stay mono */
.val { font: 700 3.2rem/.86 var(--f-txt); font-variant-numeric: tabular-nums lining-nums; color: var(--txt); letter-spacing: .01em; }
.val small { font: 400 .42em/1 var(--f-num); color: var(--txt-3); letter-spacing: 0; margin-left: .18em; }
.val.roll { animation: roll .32s cubic-bezier(.2, .7, .3, 1); }
@keyframes roll { from { transform: translateY(-.28em); opacity: .35; } }

/* key chip: [Q] */
.key { display: inline-flex; align-items: center; justify-content: center; min-width: 1.6rem; height: 1.6rem; padding: 0 .35rem; font: 400 1.1rem/1 var(--f-num); color: var(--k0); background: var(--txt-2); clip-path: polygon(.35rem 0, 100% 0, 100% calc(100% - .35rem), calc(100% - .35rem) 100%, 0 100%, 0 .35rem); }
.key.o { background: none; color: var(--txt-2); box-shadow: inset 0 0 0 1px var(--txt-3); clip-path: none; }

/* tags / trait chips */
.tag { display: inline-flex; align-items: center; gap: .25rem; height: 1.45rem; padding: 0 .4rem; font: 400 var(--t-tag)/1 var(--f-num); letter-spacing: .08em; text-transform: uppercase; border: 1px solid currentColor; color: var(--txt-2); white-space: nowrap; }
.tag.gnd { color: var(--gnd); }
.tag.air { color: var(--air); }
.tag.hair { color: var(--hos-air); }   /* hostile air */
.tag.slow { color: var(--yel); }
.tag.arm { color: #d8d2c0; }
.tag.hos { color: var(--hos); }
.tag.fast { color: #ffd36a; }
.tag.cap { color: #fff; background: var(--hos); border-color: var(--hos); }
.tag.boss { color: var(--k0); background: var(--yel); border-color: var(--yel); }
.tag svg { width: .95rem; height: .95rem; }

/* status chip (wave state etc.) */
.chip { font: 400 max(9px, 1rem)/1 var(--f-num); letter-spacing: .14em; padding: .35rem .5rem; text-transform: uppercase; white-space: nowrap; }
.chip.eng { color: #fff; background: var(--hos); }
.chip.stb { color: var(--k0); background: var(--fr); }
.chip.boss { color: var(--k0); background: var(--yel); }

/* segmented meter */
.seg { display: flex; gap: .2rem; }
.seg.dense { gap: .12rem; }
.seg i { flex: 1; height: .9rem; background: rgba(255, 255, 255, .09); transform: skewX(-24deg); }
.seg i.on { background: var(--c, var(--yel)); }
.seg i.hit { background: var(--hos); animation: segHit 1s steps(2, jump-none) infinite; }
@keyframes segHit { 50% { background: rgba(255, 74, 58, .25); } }

/* deltas next to a readout: value + reason, so a change explains itself (faded by UI.ev via el.animate) */
.dl { display: inline-flex; align-items: baseline; gap: .35rem; font: 400 1.2rem/1 var(--f-num); padding: .22rem .4rem .2rem; letter-spacing: .02em; white-space: nowrap; }
.dl small { font-size: var(--t-micro); letter-spacing: .1em; opacity: .85; }
.dl.up { color: var(--k0); background: var(--ok); }
.dl.dn { color: #fff; background: var(--hos); }
.dl.sp { color: var(--txt); background: rgba(255, 255, 255, .1); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22); }
.state { font: 400 max(9px, .95rem)/1 var(--f-num); letter-spacing: .14em; color: var(--fr); display: inline-flex; gap: .3rem; align-items: center; white-space: nowrap; }
.state::before { content: ''; width: .5rem; height: .5rem; background: currentColor; animation: blink 1.2s steps(2, jump-none) infinite; }
@keyframes blink { 50% { opacity: .2; } }

/* hidden text leaf: an element the game writes with textContent that the new layout does not show */
.leaf { display: none !important; }

/* ═══ U1 · TOP-LEFT STATUS STRIP (#top) ═══════════════════════════════════
   setT targets (#s-lives, #s-money, #s-hull) stay text-only leaves; the
   "/20", meters, deltas and states are siblings filled by UI.tick.          */
#top { position: absolute; left: var(--gap); top: var(--gap); display: flex; align-items: stretch; gap: 0; padding: .85rem 1.1rem .9rem 1.3rem; }
#top .st { display: flex; flex-direction: column; justify-content: space-between; gap: .55rem; padding: 0 1.3rem; position: relative; }
#top .st + .st::before { content: ''; position: absolute; left: 0; top: .2rem; bottom: .2rem; width: 1px; background: var(--ln-2); }
#top .st:first-child { padding-left: 0; }
#top .st:last-child { padding-right: .2rem; }
#top .row1 { display: flex; align-items: center; justify-content: space-between; gap: .7rem; height: 1.7rem; }
/* the label never gives way. A delta chip that would not fit beside it drops its reason word (core.js renderChip measures the
   glyphs: 'CREDITS  −1,234'); overflow on the chip is only a last resort, so nothing ever crosses the divider */
#top .row1 .lbl { flex: none; }
#top .row1 .dl { flex: 0 1 auto; min-width: 0; overflow: hidden; }
#top .row1 .dl small { letter-spacing: .05em; }
#top .row1 .dl.nr small { display: none; }
#top .row1 .state { flex: none; }
#top .row2 { display: flex; align-items: flex-end; gap: .8rem; height: 2.8rem; }
#top .row2 .seg { flex: 1; margin-bottom: .3rem; }
#top .st.cap { width: 16.6rem; }
#top .st.cap .val { color: var(--yel); white-space: nowrap; }
#top .st.cap .seg { --c: var(--yel); }
#top .st.cap.low .val { color: var(--warn); } #top .st.cap.low .seg { --c: var(--warn); }
#top .st.cap.crit .val { color: var(--hos); } #top .st.cap.crit .seg { --c: var(--hos); }
#top .st.cr { width: 15.6rem; } /* +1rem from Hull: room for '+66 BOUNTY' beside the label at 720p (the strip's total width is unchanged) */
#top .st.cr .val { color: var(--yel); display: inline-flex; align-items: center; white-space: nowrap; }
#top .st.cr .val .cu { font-size: .46em; color: var(--yel-d); vertical-align: 0; margin: 0 .5em 0 .15em; transform: rotate(45deg); }
#top .st.cr .row2 { justify-content: space-between; }
#top .st.hull { width: 11rem; }
#top .st.hull .seg { --c: var(--fr); }
#top .st.hull .seg i { height: .7rem; }
#top .st.hull .val { font-size: 2.6rem; color: var(--fr); white-space: nowrap; }
#top .st.hull.low .val { color: var(--warn); } #top .st.hull.low .seg { --c: var(--warn); }
#top .st.hull.down .val { color: var(--hos); font-size: 2rem; }

/* ═══ U1 · TOP-RIGHT SYSTEM ROW (#sys) ═════════════════════════════════════
   nation: a static label on its own neutral plate (not a button); perk text in the title. The emblem
   is drawn in amber here (the nation is "ours"); its own colour belongs to the menu picks.        */
#sys { position: absolute; right: var(--gap); top: var(--gap); display: flex; align-items: center; gap: .5rem; height: 3rem; }
#sys .nat { display: flex; align-items: center; gap: .6rem; padding: 0 1rem 0 .5rem; height: 100%; pointer-events: auto; cursor: help; background: var(--plate); box-shadow: inset 0 0 0 1px var(--ln-3); clip-path: polygon(.6rem 0, 100% 0, 100% 100%, 0 100%, 0 .6rem); }
#sys .nat #natEm { display: block; width: 2.1rem; height: 2.1rem; color: var(--amb); }
#sys .nat svg { width: 2.1rem; height: 2.1rem; display: block; }
#sys .nat .c { font: 400 1.1rem/1 var(--f-num); color: var(--txt-2); letter-spacing: .16em; }
#sys .nat .p { font: 700 1.25rem/1 var(--f-txt); color: var(--yel); letter-spacing: .1em; text-transform: uppercase; margin-top: .15rem; white-space: nowrap; }
/* icon buttons: the game overwrites #b-pause / #b-sound textContent ('Pause'/'Resume', 'Sound on'/'Sound off'),
   so the text is a font-size:0 leaf and the icon is a CSS mask on ::after. State = class (.on paused, .off muted). */
.ib { width: 3rem; height: 3rem; position: relative; font-size: 0; color: var(--txt-2); background: var(--ln); clip-path: polygon(.6rem 0, 100% 0, 100% calc(100% - .6rem), calc(100% - .6rem) 100%, 0 100%, 0 .6rem);
  --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M9 6h5v20H9zM18 6h5v20h-5z'/%3E%3C/svg%3E"); }
.ib::before { content: ''; position: absolute; inset: 1px; background: var(--fill-solid); clip-path: inherit; }
.ib::after { content: ''; position: absolute; inset: .75rem; background: currentColor; -webkit-mask: var(--ico) center / contain no-repeat; mask: var(--ico) center / contain no-repeat; }
.ib:hover { color: var(--yel); background: var(--amb); }
.ib:focus-visible { outline: none; color: var(--yel); background: var(--yel); }
#b-pause.on { color: var(--k0); background: var(--yel); --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M9 5l18 11L9 27z'/%3E%3C/svg%3E"); }
#b-pause.on::before { background: var(--yel); }
#b-sound { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M4 11h6l8-6.5v23L10 21H4z'/%3E%3Cpath d='M21.5 10.5a8 8 0 0 1 0 11M25.5 6.5a13.5 13.5 0 0 1 0 19' fill='none' stroke='%23000' stroke-width='2.6'/%3E%3C/svg%3E"); }
#b-sound.off { color: var(--txt-3); --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M4 11h6l8-6.5v23L10 21H4z'/%3E%3Cpath d='M21 11.5l9 9M30 11.5l-9 9' fill='none' stroke='%23000' stroke-width='2.8'/%3E%3C/svg%3E"); }
#b-menu { --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M5 7h22v3.4H5zM5 14.3h22v3.4H5zM5 21.6h15v3.4H5z'/%3E%3C/svg%3E"); }

/* ═══ U1 · COMMS LOG + ACTIVE EFFECT (#log) ═══════════════════════════════
   One stack under the status strip. Pinned .fx row while an ability effect
   runs (Sanctions: name, effect, seconds left, draining bar), then at most
   3 event lines on solid plates, newest on top; each drops ~6 s (game time)
   after its last update. Click-through.                                     */
#log { position: absolute; left: var(--gap); top: 9.2rem; display: flex; flex-direction: column; gap: .25rem; font: 400 1.08rem/1.2 var(--f-num); letter-spacing: .04em; }
/* a line: time | .m (title, then the detail). The detail wraps onto its own row under the title when both do not fit, so the
   lane, the Capitol loss or the attacker is never cut ('SIEGE CRAWLERS LEAKED ×2' / 'CAPITOL −6 · SOUTH LANE') */
#log > div { display: flex; gap: .7rem; align-items: baseline; padding: .32rem .7rem .32rem .55rem; background: var(--plate); box-shadow: inset 2px 0 0 var(--txt-3); color: var(--txt-2); width: 30rem; white-space: nowrap; animation: logIn .22s ease-out; }
#log > div > .t { flex: none; }
#log > div > .m { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: .15rem .7rem; }
#log > div b { font-weight: 400; color: var(--txt); }
#log > div .d { min-width: 0; white-space: normal; }
@keyframes logIn { from { opacity: 0; transform: translateX(-.8rem); } }
#log .t { color: var(--txt-3); }
#log .h { box-shadow: inset 2px 0 0 var(--hos); } #log .h b { color: #ff7a70; }
#log .h.air { box-shadow: inset 2px 0 0 var(--hos-air); } #log .h.air b { color: #ff8fe0; }
#log .f { box-shadow: inset 2px 0 0 var(--fr); } #log .f b { color: var(--fr); }
#log .o { color: var(--txt-3); }
#log .o b { color: var(--txt-2); }
#log .fx { display: grid; grid-template-columns: 1.8rem 1fr auto; gap: .2rem .6rem; align-items: center; padding: .45rem .7rem .5rem .5rem; box-shadow: inset 0 0 0 1px rgba(82, 216, 255, .45); background: linear-gradient(90deg, rgba(82, 216, 255, .14), rgba(82, 216, 255, .03)), var(--plate); }
#log .fx .ic { grid-row: span 2; align-self: center; width: 1.8rem; height: 1.8rem; color: var(--fr); }
#log .fx .ic svg { display: block; width: 100%; height: 100%; }
#log .fx .n { font: 700 1.3rem/1 var(--f-txt); letter-spacing: .12em; color: var(--fr); text-transform: uppercase; overflow: hidden; text-overflow: ellipsis; }
#log .fx .n span { color: var(--txt); font-weight: 600; letter-spacing: .06em; margin-left: .4rem; }
#log .fx .s { font: 700 1.6rem/1 var(--f-txt); color: var(--txt); font-variant-numeric: tabular-nums; }
#log .fx .s b { font-weight: 700; color: var(--txt); }
#log .fx .s small { font: 400 var(--t-micro)/1 var(--f-num); color: var(--txt-3); margin-left: .1rem; }
#log .fx .bar { grid-column: 2 / 4; height: .35rem; background: rgba(82, 216, 255, .16); }
#log .fx .bar i { display: block; height: 100%; background: var(--fr); transform-origin: left center; }
