/* ═══════════════════════════════════════════════════════════════════════
   world-hud-v2.css — THE HUD PASS'S FOUNDATION (GH #3069, slice S0).

   Kit B: the slate-and-gold chrome Wray ruled "build it" on 2026-09-24 (the
   v7 mock, audit/ui-gen/2026-09-24-hud-pass/page.src.html). This file holds
   what every later slice draws with: the tokens and five primitives, and
   (since the Pit's UI pass, #3346) the window, tab and button recipes
   promoted at its end. It restyles NOTHING that exists today. Every selector starts at
   `body.hud-v2`, which only public/js/world-hud-v2.js adds (flag
   FEATURE_WORLD_HUD_V2, or ?hud=1), so with the flag off this file is inert
   rather than absent and the page renders identically. (Not byte for byte:
   the served HTML gains this link and one script tag, plus the ASSET_V
   bump, so a client fetches the two files and re-fetches what the bump
   re-stamps.)

   ── THE CHROME PIXEL, --hv-k ────────────────────────────────────────────
   Every piece in public/assets/ui/kitb/ is at its native pixel size, one art
   pixel a PNG pixel. A nine-slice draws each rim at `slice * --hv-k` CSS px,
   so every rim is the same whole number of pixels and none lands on a half.
   The mock drew kit B at 2 on its 1920x1080 stage, so --hv-k is 2 there.
   It is round(min(width / 960, height / 540)), never below 1 and never
   above 4 (the steps stop there, a 5K screen draws at 4): the same
   min() the engine's letterbox takes (world-frame.js fit()), so a wide,
   short screen is sized by its height and the chrome keeps its share of
   the picture. Each step needs BOTH edges:

       1   under 1440 wide, or under 810 tall  (a phone; a 1366 or 1280 laptop)
       2   from 1440x810   (1440x900, 1920x1080: the mock's size; 2560x1080)
       3   from 2400x1350  (2560x1440, 3440x1440)
       4   from 3360x1890  (3840x2160)

   One consequence to look at on a real laptop in S1: at 1280 to 1439 wide
   kit B draws at 1, about 0.67 to 0.75 of its share at 1920, while the v1
   chrome still scales with --fs. (Looked at, S10: the two plates take their
   own k 2 from 1280x700, world-plate.css, as the tracker and the minimap
   already did; the chat keeps k 1.)

   Why not --fs, the engine's picture scale (3 at 1920 under full bleed)?
   Because it is the 3D picture's scale, not the chrome's: tying kit B to it
   makes every piece 1.5x the mock at 1920 (the critic's pass on #3069).
   And why a step and not calc(): a rim must be a whole number of pixels,
   and a media query is the rounding every browser the world supports has.

   ── WHERE THE TOKENS LIVE ───────────────────────────────────────────────
   On `body.hud-v2`, never :root. A CSS variable resolves where it is
   declared, and the engine publishes its own scale on <body>; a token that
   ever derives from one must sit where that value is.

   For the same reason there is NO derived pixel token (no `--hv-px:
   calc(var(--hv-k) * 1px)`): it would be worked out once on <body> and
   inherited as `calc(2 * 1px)`, so a slice that sets --hv-k on its own
   element (a phone band, say) would change nothing. Every length here is
   written `calc(N * var(--hv-k) * 1px)`, which reads --hv-k on the element
   it is drawing, so a local --hv-k works.

   ── THE LAYER ───────────────────────────────────────────────────────────
   `skin`: the primitives are dressing, the lowest layer that still beats
   world-skin.css at equal specificity (this file loads after it). A HUD
   corner slice that has to out-rank world-albion.css adds its own
   `@layer corners` block, in its own file or here, and registers it in
   __tests__/worldCssLayers.test.js LAYER_OF.
   ═══════════════════════════════════════════════════════════════════════ */
@layer base, module, skin, nerm, corners;

@layer skin {
/* ── tokens ──────────────────────────────────────────────────────────── */
body.hud-v2 {
  --hv-k: 1;

  /* kit B's palette (the mock's .stage tokens, and the pieces' own bodies) */
  --hv-black: #06080c;
  --hv-well: #0d1219;
  --hv-slate: #19212b;
  --hv-slate-2: #222c38;
  --hv-slate-body: #3a4760;        /* slate-window.png's body */
  --hv-line: #2e3a49;
  --hv-gold: #a28155;
  --hv-gold-2: #caa982;
  --hv-gold-hi: #e3c79a;
  --hv-ink: #f0e2c6;
  --hv-ink-slate: #d9cdb2;         /* body text on a slate window */
  /* the quiet inks, lifted to 4.5:1 or better on the slate (#27303d) and
     the name plate (#343b4e): the mock's #9d8a6d and #8a98aa measured 4.1
     and 3.8 at 8px pixel type (#3069 S10, audit C14) */
  --hv-dim: #b3a07f;
  --hv-mute: #aab6c6;
  --hv-hint: #9aa6b6;
  --hv-red: #a3343b;               /* title.png's ribbon, and the selected tab */
  --hv-hp: #c8372d;
  --hv-hp-2: #ef6552;
  --hv-xp: #d8a23d;
  --hv-energy: #3f7fe0;
  --hv-friend: #e7c77f;
  --hv-foe: #ef5646;
  --hv-ok: #7fcf8f;
  --hv-sys: #93b5d8;               /* a System line in chat */

  /* the arena's stat palette, as public/css/variables-v2.css --stat-* */
  --stat-atk: #e85a6a;
  --stat-hp: #6acd8a;
  --stat-spd: #6ac8d8;
  --stat-def: #b088e8;
  --stat-luck: #d4a64b;

  /* bitmap type only (#1953); the New Rocker title face is preloaded by the page */
  --hv-f-px: 'Press Start 2P', monospace;
  --hv-f-vt: 'VT323', monospace;
  --hv-f-tome: 'New Rocker', 'Press Start 2P', monospace;
}
@media (min-width: 1440px) and (min-height: 810px) { body.hud-v2 { --hv-k: 2; } }
@media (min-width: 2400px) and (min-height: 1350px) { body.hud-v2 { --hv-k: 3; } }
@media (min-width: 3360px) and (min-height: 1890px) { body.hud-v2 { --hv-k: 4; } }

/* ── the primitives ──────────────────────────────────────────────────────
   Each is a nine-slice from kitb/ at the chrome pixel. The border is zeroed
   because a nine-slice paints from border-image-width alone, and a real
   border would also shrink the content box. Padding is the rim, so content
   starts inside the drawn frame. Slices are the ones the mock measured.
   Only the bar sets `display` (its height IS its shape, and a <span> would
   ignore it); the other four are for a box the owner already lays out as
   block, flex or grid. */
body.hud-v2 .hv-frame,
body.hud-v2 .hv-slate,
body.hud-v2 .hv-well,
body.hud-v2 .hv-slot,
body.hud-v2 .hv-bar {
  box-sizing: border-box;
  border-style: solid;
  border-width: 0;
  image-rendering: pixelated;
}

/* the gold frame: door.png, rim 8 */
body.hud-v2 .hv-frame {
  border-image: url('/assets/ui/kitb/door.png?v=2026-09-24a') 8 fill / calc(8 * var(--hv-k) * 1px) stretch;
  padding: calc(8 * var(--hv-k) * 1px);
}
/* selected: dooron.png is door.png plus a 3px glow all round, so its rim of
   11 is drawn 3 outside the box and the gold lands where the plain one's did */
body.hud-v2 .hv-frame.is-on {
  border-image: url('/assets/ui/kitb/dooron.png?v=2026-09-24a') 11 fill / calc(11 * var(--hv-k) * 1px) / calc(3 * var(--hv-k) * 1px) stretch;
}

/* the slate plate: panel.png, the glass slate with gold corner studs, rim 12 */
body.hud-v2 .hv-slate {
  border-image: url('/assets/ui/kitb/panel.png?v=2026-09-24a') 12 fill / calc(12 * var(--hv-k) * 1px) stretch;
  padding: calc(12 * var(--hv-k) * 1px);
  color: var(--hv-ink-slate);
}

/* the inset well: well.png, rim 10 */
body.hud-v2 .hv-well {
  border-image: url('/assets/ui/kitb/well.png?v=2026-09-24a') 10 fill / calc(10 * var(--hv-k) * 1px) stretch;
  padding: calc(10 * var(--hv-k) * 1px);
}

/* an item or ability slot: slot1.png, rim 5; slot2-5 are the rarity rims */
body.hud-v2 .hv-slot {
  border-image: url('/assets/ui/kitb/slot1.png?v=2026-09-24a') 5 fill / calc(5 * var(--hv-k) * 1px) stretch;
  padding: calc(5 * var(--hv-k) * 1px);
}
body.hud-v2 .hv-slot.hv-r2 { border-image-source: url('/assets/ui/kitb/slot2.png?v=2026-09-24a'); }
body.hud-v2 .hv-slot.hv-r3 { border-image-source: url('/assets/ui/kitb/slot3.png?v=2026-09-24a'); }
body.hud-v2 .hv-slot.hv-r4 { border-image-source: url('/assets/ui/kitb/slot4.png?v=2026-09-24a'); }
body.hud-v2 .hv-slot.hv-r5 { border-image-source: url('/assets/ui/kitb/slot5.png?v=2026-09-24a'); }

/* a bar: trough.png (15 tall, rim 4) and a segmented fill (hpfill.png and
   enfill.png, 9 tall) inset 3, so at its natural height every row of the
   fill is one art pixel. The owner sets --hv-fill (0 to 1, clamped) on the
   bar or the fill; nothing here animates, so a bar that has no value yet
   draws empty, not a guess. Where the browser has round(), the fill's width
   is snapped down to a whole art pixel, so a value like .3 does not cut a
   segment mid-pixel.

   ⚠ FOR S1: this is the pixel-clean size, NOT the mock's. The v7 mock drew
   its hero HP bar 20px tall with an 8px fill at 1920 (hpfill's 9 rows
   squashed to 4 art rows, so not whole pixels), its energy bar 16px and its
   XP bar 12px. At --hv-k 2 this bar is 30px with an 18px fill, the XP bar
   24px with a 12px fill: 1.5x and 2x the mock. A slice that wants the
   mock's compact bar decides that on purpose, knowing the rows go uneven. */
body.hud-v2 .hv-bar {
  display: block;
  position: relative;
  height: calc(15 * var(--hv-k) * 1px);
  border-image: url('/assets/ui/kitb/trough.png?v=2026-09-24a') 4 fill / calc(4 * var(--hv-k) * 1px) stretch;
}
body.hud-v2 .hv-bar > i {
  position: absolute;
  left: calc(3 * var(--hv-k) * 1px);
  top: calc(3 * var(--hv-k) * 1px);
  bottom: calc(3 * var(--hv-k) * 1px);
  width: calc((100% - 6 * var(--hv-k) * 1px) * clamp(0, var(--hv-fill, 0), 1));
  /* the cap once, then one even segment repeated: no seam (#3069 S10, the
     plate's own bars in world-plate.css say why) */
  background:
    url('/assets/ui/kitb/hpcap.png?v=2026-09-25a') left center / auto 100% no-repeat,
    url('/assets/ui/kitb/hpseg.png?v=2026-09-25a') left center / auto 100% repeat-x;
  image-rendering: pixelated;
}
/* A declaration holding var() cannot fall back to the one above if the
   browser rejects it (it goes invalid at computed-value time, width: auto,
   an empty bar), so the snap sits behind @supports instead. */
@supports (width: round(down, 5px, 2px)) {
  body.hud-v2 .hv-bar > i {
    width: round(down, calc((100% - 6 * var(--hv-k) * 1px) * clamp(0, var(--hv-fill, 0), 1)), calc(var(--hv-k) * 1px));
  }
}
body.hud-v2 .hv-bar.hv-en > i {
  background-image: url('/assets/ui/kitb/encap.png?v=2026-09-25a'), url('/assets/ui/kitb/enseg.png?v=2026-09-25a');
}
/* xpfill.png is 6 rows, one gold run with no segments. The XP trough is 12
   rows, not 15, so its fill (12 less the inset of 3 each side) is exactly 6
   rows and the image scales by a whole --hv-k. The trough's middle rows are
   one flat slate, so drawing it 3 rows shorter loses nothing. Across, the
   run has no segments, so it stretches. */
body.hud-v2 .hv-bar.hv-xp {
  height: calc(12 * var(--hv-k) * 1px);
}
body.hud-v2 .hv-bar.hv-xp > i {
  background: url('/assets/ui/kitb/xpfill.png?v=2026-09-24a') left center / 100% 100% no-repeat;
}

/* ── the promoted recipes (#3346, the Pit's UI pass, batch 1) ─────────────
   The slate window, its red title ribbon, the red close, the HUD tab, the
   slate and gold buttons, the dark tip plate and the parchment chip were
   written three times: world-windows-v2.css §1-§3 (keyed on .ws-sheet under
   .skin-majesty), world-map-v2.css, and the Pit's venue-build.css. The
   Pit's own page has neither .ws-sheet nor .skin-majesty, so it could reach
   none of them. They are promoted here as primitives, drawn at the chrome
   pixel like the five above. INERT IN THE WORLD: no world element carries
   these classes (the world's own windows keep their §1-§3 rules), so the
   world renders exactly as before. The venue sets body.hud-v2 on its own
   document when FEATURE_PIT_UI_V2 is on (public/js/venue-ui2.js). Batch 2
   added the in-window red tab (.hv-tab.red), the flat inset (.hv-inset) and
   the keycap (.hv-key), for the Pit's result sheet and TABLE window.

   ⛔ THE RIM IS THE BORDER HERE, not the padding (the §3 planks' way, not
   .hv-frame's): an owner's own padding is then the space inside the rim,
   and a padding it sets can never eat the drawn edge.

   ⛔ LAYERED, so an UNLAYERED rule on the same element wins whatever its
   specificity. An owner whose element already has unlayered styles (the
   venue's inline sheet) takes those properties back with `revert-layer`,
   which hands them to the rule here instead of copying it (venue-ui2.css). */
body.hud-v2 .hv-tip,
body.hud-v2 .hv-btn,
body.hud-v2 .hv-tab,
body.hud-v2 .hv-window {
  box-sizing: border-box;
  border-style: solid;
  image-rendering: pixelated;
}

/* the dark plate over the picture: tip.png, rim 5 (the world's door tip at
   the same pixel, world-doors-v2.css). Every plate the Pit's broadcast puts
   over the picture wears it (the mock's round 5 rule). */
body.hud-v2 .hv-tip {
  border-width: calc(5 * var(--hv-k) * 1px);
  border-image: url('/assets/ui/kitb/tip.png?v=2026-10-04a') 5 fill / calc(5 * var(--hv-k) * 1px) stretch;
  background: none;
  box-shadow: none;
  padding: calc(1 * var(--hv-k) * 1px) calc(2 * var(--hv-k) * 1px);
  color: var(--hv-ink);
}

/* a button: btn.png (69x18, rim 3 3 5 3). Its natural height is its art's
   18 rows, so the word sits on the plank's face; the lettering is §21's (the
   pixel face in capitals, 1px apart). The 44px thumb floor is the owner's,
   because only the owner knows it is on a touch screen. */
body.hud-v2 .hv-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(3 * var(--hv-k) * 1px);
  margin: 0;
  min-height: calc(18 * var(--hv-k) * 1px);
  border-width: calc(3 * var(--hv-k) * 1px) calc(3 * var(--hv-k) * 1px) calc(5 * var(--hv-k) * 1px) calc(3 * var(--hv-k) * 1px);
  border-image: url('/assets/ui/kitb/btn.png?v=2026-09-24a') 3 3 5 3 fill / calc(3 * var(--hv-k) * 1px) calc(3 * var(--hv-k) * 1px) calc(5 * var(--hv-k) * 1px) calc(3 * var(--hv-k) * 1px) stretch;
  background: none;
  box-shadow: none;
  padding: 0 calc(5 * var(--hv-k) * 1px);
  font: 400 8px/1 var(--hv-f-px);
  letter-spacing: 1px;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--hv-ink);
  text-shadow: 0 1px 0 rgba(0, 0, 0, .6);
  white-space: nowrap;
  cursor: pointer;
}
body.hud-v2 .hv-btn:hover,
body.hud-v2 .hv-btn:focus-visible { filter: brightness(1.18); }
body.hud-v2 .hv-btn:focus-visible { outline: 2px solid var(--hv-gold-hi); outline-offset: 2px; }
/* the one thing a surface asks of you: btngold.png, ink on gold (7.5:1) */
body.hud-v2 .hv-btn.gold {
  border-image-source: url('/assets/ui/kitb/btngold.png?v=2026-09-24a');
  color: #2a1c0c;
  text-shadow: none;
}
/* chosen, or open: tabon.png (the tan the mock's segmented rows light, rim
   4 3 5 3). The border stays the plank's, so nothing moves when it lights;
   only the drawn rim's top row is one art pixel deeper. */
body.hud-v2 .hv-btn.is-on,
body.hud-v2 .hv-btn[aria-pressed='true'],
body.hud-v2 .hv-btn[aria-expanded='true'] {
  border-image-source: url('/assets/ui/kitb/tabon.png?v=2026-09-24a');
  border-image-slice: 4 3 5 3 fill;
  border-image-width: calc(4 * var(--hv-k) * 1px) calc(3 * var(--hv-k) * 1px) calc(5 * var(--hv-k) * 1px) calc(3 * var(--hv-k) * 1px);
  color: #3b2a18;
  text-shadow: none;
  filter: none;
}
body.hud-v2 .hv-btn:disabled,
body.hud-v2 .hv-btn[aria-disabled='true'] {
  cursor: default;
  filter: grayscale(.55) brightness(.82);
}

/* a tab over the picture: the chat's (chat-tab.png 44x19, chat-tabon.png
   44x26, both rim 5 5 1 5; world-chat-v2.css), tan when on. The chosen one
   stands two chrome pixels taller, as the chat's does, so a row of them
   wants `align-items: flex-end`. */
body.hud-v2 .hv-tab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  min-height: calc(19 * var(--hv-k) * 1px);
  border-width: calc(5 * var(--hv-k) * 1px) calc(5 * var(--hv-k) * 1px) calc(1 * var(--hv-k) * 1px) calc(5 * var(--hv-k) * 1px);
  border-image: url('/assets/ui/kitb/chat-tab.png?v=2026-09-24a') 5 5 1 5 fill / calc(5 * var(--hv-k) * 1px) calc(5 * var(--hv-k) * 1px) calc(1 * var(--hv-k) * 1px) calc(5 * var(--hv-k) * 1px) stretch;
  background: none;
  box-shadow: none;
  padding: 0 calc(2 * var(--hv-k) * 1px);
  font: 400 8px/1 var(--hv-f-px);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #aeb8c8;
  text-shadow: none;
  white-space: nowrap;
  cursor: pointer;
  opacity: 1;
}
body.hud-v2 .hv-tab:hover { color: #d4dbe6; }
body.hud-v2 .hv-tab:focus-visible { outline: 2px solid var(--hv-gold-hi); outline-offset: 1px; }
body.hud-v2 .hv-tab.is-on,
body.hud-v2 .hv-tab[aria-selected='true'] {
  border-image-source: url('/assets/ui/kitb/chat-tabon.png?v=2026-09-24a');
  min-height: calc(21 * var(--hv-k) * 1px);
  color: #3b2a18;
}
body.hud-v2 .hv-tab:disabled {
  cursor: not-allowed;
  color: #6f7a8a;
}
/* a tab INSIDE a window (#3346 batch 2): slate-tab.png (23x57, rim 6), the
   chosen one kit B's red and gold with no arrow (tab-on-red.png, rim 6):
   world-windows-v2.css §2's in-window row (a station's tabs, the
   Leaderboard's Today / Season / All time), promoted. The same height lit
   or not, so a row of them never moves. */
body.hud-v2 .hv-tab.red {
  min-height: calc(19 * var(--hv-k) * 1px);
  border-width: calc(6 * var(--hv-k) * 1px);
  border-image: url('/assets/ui/kitb/slate-tab.png?v=2026-09-24a') 6 fill / calc(6 * var(--hv-k) * 1px) stretch;
  padding: 0 calc(2 * var(--hv-k) * 1px);
  color: #d9cdb2;
  text-shadow: 0 2px 0 rgba(0, 0, 0, .55);
}
body.hud-v2 .hv-tab.red:hover { color: #efe3c8; filter: brightness(1.15); }
body.hud-v2 .hv-tab.red.is-on,
body.hud-v2 .hv-tab.red[aria-selected='true'] {
  border-image-source: url('/assets/ui/kitb/tab-on-red.png?v=2026-09-24a');
  min-height: calc(19 * var(--hv-k) * 1px);
  color: #f7e6c4;
  text-shadow: 0 2px 0 #5e1414;
  filter: none;
}

/* a panel INSIDE a window: flat, never a second frame (the mock's round 5:
   #1c2330 with a bronze rim one chrome pixel wide, 2px at the mock's 2) */
body.hud-v2 .hv-inset {
  box-sizing: border-box;
  background: #1c2330;
  box-shadow: inset 0 0 0 calc(1 * var(--hv-k) * 1px) #56472f;
  padding: calc(4 * var(--hv-k) * 1px);
}

/* a keycap: the action bar's (world-actionbar.css .ab2-kc), at the chrome
   pixel. A button's number where a table names it. */
body.hud-v2 .hv-key {
  display: inline-grid;
  place-items: center;
  box-sizing: border-box;
  min-width: calc(16 * var(--hv-k) * 1px);
  height: calc(16 * var(--hv-k) * 1px);
  padding: 0 calc(3 * var(--hv-k) * 1px);
  font: 400 8px/1 var(--hv-f-px);
  color: var(--hv-ink);
  background: #0b1016;
  box-shadow: 0 0 0 calc(1 * var(--hv-k) * 1px) var(--hv-black), inset 0 0 0 calc(1 * var(--hv-k) * 1px) #56472f;
  text-shadow: none;
}

/* a small parchment chip: dark ink on drawn paper with a dark rim (the
   mock's small-chip rule; the paper comes from world-chrome.js, and flat
   #d9c49a stands in until it has installed) */
body.hud-v2 .hv-chip {
  display: inline-block;
  box-sizing: border-box;
  border: 0;
  padding: calc(2 * var(--hv-k) * 1px) calc(3 * var(--hv-k) * 1px) calc(1 * var(--hv-k) * 1px);
  background-color: #d9c49a;
  background-image: var(--wc-parchment, none);
  background-size: var(--wc-parchment-tile, auto);
  box-shadow: 0 0 0 calc(1 * var(--hv-k) * 1px) #0b0f15;
  font: 400 8px/1 var(--hv-f-px);
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--wc-ink-on-parchment, #33240f);
  text-shadow: none;
  white-space: nowrap;
  image-rendering: pixelated;
}

/* a window: slate-window.png (141x94, rim 18, gold corner ornaments round a
   flat middle), world-windows-v2.css §1. The colour under it is the floor if
   the art has not decoded, clipped so no straight edge shows behind the
   corners. */
body.hud-v2 .hv-window {
  border-width: calc(18 * var(--hv-k) * 1px);
  border-image: url('/assets/ui/kitb/slate-window.png?v=2026-09-24a') 18 fill / calc(18 * var(--hv-k) * 1px) stretch;
  background: var(--hv-slate-body);
  background-clip: padding-box;
  box-shadow: none;
  color: var(--hv-ink-slate);
}
/* its title on the red ribbon (title.png 116x28, rim 2 24 9 24), straddling
   the top edge 11 chrome pixels above it; the owner places it (§1's .ws-
   sheet-title). The tome is a 16px face, so 16 at the chrome pixel. */
body.hud-v2 .hv-title {
  box-sizing: border-box;
  height: calc(28 * var(--hv-k) * 1px);
  min-width: calc(116 * var(--hv-k) * 1px);
  border-style: solid;
  border-width: 0;
  border-image: url('/assets/ui/kitb/title.png?v=2026-09-24a') 2 24 9 24 fill / calc(2 * var(--hv-k) * 1px) calc(24 * var(--hv-k) * 1px) calc(9 * var(--hv-k) * 1px) calc(24 * var(--hv-k) * 1px) stretch;
  padding: calc(2 * var(--hv-k) * 1px) calc(28 * var(--hv-k) * 1px) calc(9 * var(--hv-k) * 1px);
  background: none;
  font-family: var(--hv-f-tome);
  font-size: calc(16 * var(--hv-k) * 1px);
  line-height: 1;
  white-space: nowrap;
  color: #f7e6c4;
  text-shadow: 0 calc(1 * var(--hv-k) * 1px) 0 #5e1414;
  image-rendering: pixelated;
}
/* the red close (close.png 25x27, whole at the chrome pixel). Its X is the
   art's, so the button's own word goes; its accessible name stays. */
body.hud-v2 .hv-close {
  box-sizing: border-box;
  width: calc(25 * var(--hv-k) * 1px);
  height: calc(27 * var(--hv-k) * 1px);
  margin: 0;
  padding: 0;
  border: 0;
  background: url('/assets/ui/kitb/close.png?v=2026-09-24a') center / 100% 100% no-repeat;
  box-shadow: none;
  color: transparent;
  font-size: 0;
  cursor: pointer;
  image-rendering: pixelated;
}
body.hud-v2 .hv-close:hover { filter: brightness(1.15); }
body.hud-v2 .hv-close:focus-visible { outline: 2px solid var(--hv-gold-hi); outline-offset: 2px; }

/* ── THE CURRENCY ICONS (Wray, 2026-10-04: picks A and F) ─────────────────
   "we need an icon for infamy and obols, so they are easier to recognise from
   lots of in game surfaces." A class on the label or the price puts the icon
   in front of it: `cur-obol` (the silver cat coin) and `cur-infamy` (the
   laurel with the fang). 32 art pixels drawn at 8 * k, so 16 px at k 2:
   a whole half, the size the pick sheet showed them at. Source and the
   other candidates: audit/chrome/2026-10-04-currency-icons/. */
body.hud-v2 .cur-obol::before,
body.hud-v2 .cur-infamy::before {
  content: '';
  display: inline-block;
  width: calc(8px * var(--hv-k, 2));
  height: calc(8px * var(--hv-k, 2));
  margin-right: calc(2px * var(--hv-k, 2));
  vertical-align: -0.2em;
  background: center / contain no-repeat;
  image-rendering: pixelated;
}
body.hud-v2 .cur-obol::before { background-image: url('/assets/ui/kitb/obol.png?v=2026-10-04a'); }
body.hud-v2 .cur-infamy::before { background-image: url('/assets/ui/kitb/infamy.png?v=2026-10-04a'); }

/* ── SPEECH OVER CATS (#3802) ─────────────────────────────────────────────
   Ruled 2026-10-05 off the pick sheet (audit/artifacts/speech-bubble-picks):
   style A, the dark plate every overlay over the picture already wears
   (tip.png, rim 5), and its sizes LOCKED the same day: VT323 at 12 chrome
   pixels with an 18px floor, line height 1.05, at most the larger of 200px
   and 128 chrome pixels wide. The engine owns WHERE a bubble is (app.js
   updateBubbles, Jack's, untouched); this lifts it over the name above a
   cat by `--np-lift`, the name's height that world-nameplates.js publishes
   on the bubble layer, and owns how it looks. It beats the
   template's own `.bubble` and its `body.psx` box because the template is
   @layer base. The tail continues the plate's bottom edge pixel for pixel:
   its gold line opens, then narrows to a point in the plate's own colours. */
body.hud-v2 #bubbles .bubble {
  margin-top: calc(-1 * var(--np-lift, 0px));
  width: max-content;
  max-width: max(200px, calc(128 * var(--hv-k) * 1px));
  padding: 0 calc(1 * var(--hv-k) * 1px);
  border-style: solid;
  border-width: calc(5 * var(--hv-k) * 1px);
  border-image: url('/assets/ui/kitb/tip.png?v=2026-10-04a') 5 fill / calc(5 * var(--hv-k) * 1px) stretch;
  border-radius: 0;
  background: none;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  font-family: var(--hv-f-vt);
  font-size: max(18px, calc(12 * var(--hv-k) * 1px));
  line-height: 1.05;
  color: var(--hv-ink);
  text-shadow: none;
  image-rendering: pixelated;
}
body.hud-v2 #bubbles .bubble::after {
  display: block;
  content: '';
  position: absolute;
  left: 50%;
  top: calc(100% + 3 * var(--hv-k) * 1px);
  bottom: auto;
  margin-left: 0;
  width: calc(5 * var(--hv-k) * 1px);
  height: calc(4 * var(--hv-k) * 1px);
  border: 0;
  transform: translateX(-50%);
  background: url('/assets/ui/kitb/bubble-tail.png?v=2026-10-05a') 0 0 / 100% 100% no-repeat;
  image-rendering: pixelated;
}
}
/* end of @layer skin */
