/* ---- HUD quest tracker ------------------------------------------------------------------------
   The card under the minimap: what the world is asking of you, as against the status block on the
   left, which is what you are. Capped at MAX_TRACKED_QUESTS in GameHUD; the full log is one keypress
   away (Q), which is where a tracker should send you rather than trying to be the log itself.
   It carries `.v-page`, so its frame comes from the shared furniture rather than a fourth
   hand-rolled copy — the inline #3b3170 it used to use appears in no design token. */
/* Secondary tier: glanceable furniture, not a page you sit and read. See ORNAMENT TIERS. */
/* Clears the minimap AND its zoom row. The stack above is: 14 top inset + 168 plate + 8 gap +
   26 button = 216, so 224 leaves the same 8px breath under the buttons that they have above them.
   Was 200, which was correct while the zoom controls hung off the plate's right rim and is not now
   that they sit underneath it — moving them without moving this put the buttons behind the card. */
.hud-quests { position: absolute; right: 14px; top: 224px; z-index: 16; pointer-events: none;
  width: 208px; padding: 9px 12px 10px; }
.hud-quests-title { font-family: var(--font-banner); font-size: 10px; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: var(--gold-hi);
  margin-bottom: 6px; }
.hud-quest-line { font-size: 12px; line-height: 1.35; color: var(--ink-soft);
  text-shadow: 0 1px 2px #000; }
.hud-quest-line + .hud-quest-line { margin-top: 5px; }

/* ---- HUD minimap ------------------------------------------------------------------------------
   A LIVING SURVEY bound into the Ledger — and it is now SQUARE, which the earlier round version was
   not. The argument for the disc was that a circular crop tells no lie about heading; the argument
   against it is stronger and simpler, and it is what the plate is actually showing: every map in
   this game is a SQUARE tile grid, and the crop this panel draws is a square window onto it. A
   round frame over a square crop throws the four corners away — real, visible, walkable ground that
   the canvas has already drawn — and rounds off the map's own edge into an arc it does not have.
   The frame now matches the thing framed.
   The plate clips; the frame, the compass mark and the zoom controls all sit OUTSIDE that clip, so
   the rounding of the clip cannot cut them. */
.hud-minimap-disc { position: absolute; inset: 0; border-radius: 4px; overflow: hidden;
  background: #0a0b1a; }
.hud-minimap-disc > canvas { width: 100%; height: 100%; display: block; }
/* The bezel the plate is set into. Gold as a RIM, never a fill (VIL · Colour). */
.hud-minimap-ring { position: absolute; inset: -2px; border-radius: 5px; pointer-events: none;
  border: 2px solid var(--gold);
  box-shadow: 0 0 14px -3px var(--gold-glow), inset 0 0 18px -6px rgba(0,0,0,.9); }
/* North. The one mark a survey cannot be read without, so it is the one mark that earns its place
   on the rim. The map is north-up (see drawMinimap), so this is a fact and not a decoration.

   IT SITS ABOVE THE PLATE, NOT ON IT. At `top: -9px` the badge straddled the rim and covered the
   top-centre of the survey — which is exactly where a NORTH portal's marker is drawn, so the one
   direction the compass exists to name was the one whose exit it hid. `bottom: 100%` lifts it clear
   of the disc entirely, so it can overlap nothing the map draws. */
.hud-minimap-n { position: absolute; bottom: calc(100% + 2px); left: 50%; transform: translateX(-50%);
  padding: 0 5px; border-radius: 3px; pointer-events: none;
  background: linear-gradient(180deg, #2b2360, #16113a);
  border: 1px solid var(--gold-deep); color: var(--gold-hi);
  font-family: var(--font-banner); font-size: 10px; font-weight: 600; letter-spacing: .1em;
  line-height: 15px; }
/* CENTRED IN A ROW BELOW THE PLATE. They used to be a column stacked against the right-hand rim,
   which overlapped the survey it controls and pushed the eye off-centre. Hanging them BELOW is safe
   in the one direction the old note worried about — the assembly is anchored top-right, so growth
   downward has the whole screen to grow into, where growth rightward lands in the 14px margin.
   Centred with left:50% + translateX(-50%) rather than a full-width flex row, so the row's width is
   its own content and the buttons sit under the plate's midline whatever the plate's size. */

/* WHERE YOU ARE, under the plate and above the controls: the map's name, and your coordinates.
   Two rows in one block so the name can be long and the numbers stay on their own line — and the
   numbers are tabular, because a coordinate that shifts left and right as you walk is a readout
   that twitches. */
/* ONE INLINE ROW under the plate (owner's call): the map's name on the left, the coordinates in
   the middle, the zoom buttons on the right. Stacked, it was three bands of furniture hanging off
   a 168px plate; in a row it reads as one caption bar the width of the map. */
/* WIDER THAN THE PLATE, leftward. 168px cannot hold a zone name, a coordinate and two buttons
   without ellipsising the name to "The Briarw…", and the assembly is anchored to the screen's
   top-right corner — so there is open HUD to the left and none to the right. */
/* THE NAME STARTS AT THE PLATE'S LEFT EDGE (owner's call). It used to begin 76px to the left of
   it, on the argument that a wider row ellipsises fewer zone names — which bought a few characters
   and cost the one alignment the assembly had. The map's name is a caption for the map, and a
   caption that starts to the left of the thing it captions reads as a stray label. The full name
   is on the element's `title`, so nothing is actually lost to the truncation. */
.hud-minimap-under { position: absolute; left: 0; right: 0; top: 100%; margin-top: 5px;
  /* TOP-ALIGNED (owner's call): the map's name lines up with the TOP of the zoom discs rather than
     with their middle, so the row reads off one line instead of two. */
  display: flex; flex-direction: row; align-items: flex-start; justify-content: space-between;
  gap: 8px; }
/* THE NAME AND ITS FAST-TRAVEL CARET, on one line. `min-width: 0` on the wrapper is what lets the
   name ellipsise instead of pushing the caret off the row — a flex child will not shrink below its
   content without it, and a long zone name would otherwise take the caret with it. */
.hud-minimap-placewrap { min-width: 0; flex: 1; display: flex; align-items: baseline; gap: 3px; }
.hud-minimap-place { min-width: 0; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font: 600 11px var(--font-banner); letter-spacing: .04em; color: var(--gold-hi);
  text-shadow: 0 1px 3px rgba(0,0,0,.9); }
/* ABOVE the plate and against its right edge, clear of the N mark on the top rim, and sized to
   FILL the gap the assembly now leaves rather than to hide in it.
   LEGIBILITY (owner's report: hard to read). It was 10px muted grey on whatever the world happens
   to be behind it, which at the top of the screen is usually bright sky. Three changes, all of
   them contrast rather than size alone: the type goes up to 11px and to the parchment ink the rest
   of the HUD's live readouts use, the figures are set bold and tabular so a walking coordinate does
   not shimmer, and the whole row gets a dark plate behind it so it is never read against terrain.
   The axis letters stay quiet — they are labels, and the numbers are the readout. */
/* ON THE SAME LINE AS THE COMPASS (owner's call). Both live above the plate, and they sat at two
   different heights — the badge 2px clear of the rim, the readout 4px, with different box heights
   underneath them — so the strip above the map read as two loose labels rather than as one row.
   The offset and the inner height are stated to MATCH `.hud-minimap-n` exactly; change one and the
   other has to move with it. */
.hud-minimap-coord { position: absolute; right: 0; bottom: calc(100% + 2px);
  display: flex; align-items: baseline; gap: 3px;
  padding: 0 6px; border-radius: 3px;
  background: rgba(10,11,26,.62);
  border: 1px solid rgba(125,90,46,.5);
  pointer-events: none; white-space: nowrap;
  font-family: var(--font-mono); font-size: 11px; font-variant-numeric: tabular-nums;
  line-height: 15px;                 /* == .hud-minimap-n, so the two plates are the same height */
  color: var(--gold-hi); text-shadow: 0 1px 3px rgba(0,0,0,.95); }
.hud-minimap-coord b { font-weight: 700; letter-spacing: .01em; }
/* The axis letter: quieter than the figure, and given a little air after the previous number so
   "X 12 Y -40" reads as two pairs rather than as one run of characters. */
.hud-minimap-coord .hud-coord-ax { font-style: normal; font-weight: 600;
  color: var(--ink-mute, #b9b3d6); }
.hud-minimap-coord .hud-coord-ax + b { margin-right: 4px; }
.hud-minimap-coord b:last-child { margin-right: 0; }

/* RIGHT-ALIGNED (owner's call), and now BELOW the caption rather than directly under the plate.
   The assembly is anchored to the screen's top-right corner, so the buttons sitting on that same
   edge puts them where the eye already is instead of on a centre line of their own. */
/* ── THE TESTING FAST-TRAVEL MENU ───────────────────────────────────────────────────────────────
   A caret beside the zone name that drops a list of map thumbnails. It hangs BELOW its own row and
   is `position: absolute` so opening it cannot reflow the caption it is attached to — the caption
   repaints every frame, and a menu that changed the row's height would make the whole HUD jump. */
.hud-travel { position: relative; flex: none; }
.hud-travel-caret { all: unset; cursor: pointer; padding: 0 2px; line-height: 1;
  font-size: 10px; color: var(--ink-mute, #b9b3d6); text-shadow: 0 1px 3px rgba(0,0,0,.9); }
.hud-travel-caret:hover { color: var(--gold-hi); }
.hud-travel-menu { display: none; position: absolute; right: 0; top: calc(100% + 4px);
  z-index: 40; width: 190px; max-height: 320px; overflow-y: auto;
  padding: 4px; border-radius: 4px;
  background: rgba(10,11,26,.96);
  border: 1px solid rgba(125,90,46,.6);
  box-shadow: 0 6px 18px rgba(0,0,0,.6); }
.hud-travel.is-open .hud-travel-menu { display: block; }
.hud-travel-row { all: unset; box-sizing: border-box; cursor: pointer;
  display: flex; align-items: center; gap: 7px; width: 100%; padding: 3px 5px; border-radius: 3px;
  font: 600 11px var(--font-banner); letter-spacing: .03em; color: var(--gold-hi); }
.hud-travel-row:hover { background: rgba(125,90,46,.30); }
/* WHERE YOU ARE, marked rather than removed: a menu that hides the current entry makes the list
   change length as you travel, and the one thing a place list should always answer is "which of
   these am I in". */
.hud-travel-row.is-here { background: rgba(125,90,46,.18); color: #fff3d8; }
.hud-travel-row.is-here::after { content: '\25C0'; margin-left: auto; font-size: 10px; opacity: .8; }
.hud-travel-thumb { flex: none; width: 34px; height: 34px; object-fit: cover; border-radius: 2px;
  border: 1px solid rgba(125,90,46,.45); background: rgba(0,0,0,.35); }

.hud-minimap-zoom { flex: none; display: flex; flex-direction: row; gap: 5px; }
/* 22px rather than 26: the row now shares the plate's width with a name and a coordinate, and the
   buttons are the one part of it that can give ground without becoming unreadable. */
.hud-minimap-btn { width: 22px; height: 22px; padding: 0; line-height: 1;
  font-family: var(--font-banner); font-size: 14px; }

/* ---- HUD hotbar -------------------------------------------------------------------------------
   The rail of things you can reach for. Class-based so it shares the Ledger's page furniture rather
   than a fifth hand-rolled frame.
   NOTE ON XP: the reference plate carries an XP rail beneath this bar as well as an XP row in the
   status block. We deliberately have only the top one. The same number in two places is the
   duplication the restraint gate exists to catch: the bottom rail would earn its place only by
   being the primary readout, and the status block already is. */
/* The two rails sit in one bottom-centred row: keys 1-9 on the left, the mount cell on its own
   rail to the right. A GAP rather than a tenth cell, because the mount is not the same kind of
   thing as the nine — those are what is in your hands, this is what you arrive on. */
.hud-hotbar-row { position: absolute; left: 50%; bottom: 16px; transform: translateX(-50%);
  display: flex; align-items: flex-end; gap: 34px; z-index: 60; pointer-events: none; }
.hud-hotbar { position: relative;
  display: flex; gap: 6px; padding: 10px 13px; pointer-events: none;
  font: 600 13px var(--font-body); }
/* The mount rail: same furniture, one cell wide. */
.hud-hotbar--mount { padding: 10px; }
/* The ammo rail, left of the nine. Same furniture again, one cell wide — it belongs to the bar
   rather than floating beside it, which is the whole reason it is a rail and not a loose badge. */
.hud-hotbar--ammo { padding: 10px; }
/* How many are left, bottom-right of the cell, where a stack count sits everywhere else in the
   game. Its own class rather than the bag's `.rpg-count`: that one is measured for a Ledger cell. */
/* COOLDOWN (GameHUD.paintCooldown): a clock sweep whose shaded wedge is the time LEFT, a dimmed
   icon underneath, a bright rim on the sweep's edge, and a one-shot flash when it comes ready. */
.hud-slot-cd-sweep { position: absolute; inset: 0; border-radius: 4px; pointer-events: none; display: none;
  /* A COLOURED wedge, not a black one: dark shade vanished into dark icons. Indigo-blue at 70%
     reads against every icon in the set, and a bright cyan leading edge marks where the sweep is. */
  background: conic-gradient(from 0deg,
    transparent calc(360deg - var(--cd, 0deg)),
    rgba(120,220,255,.95) calc(360deg - var(--cd, 0deg)),
    rgba(120,220,255,.95) calc(360deg - var(--cd, 0deg) + 4deg),
    rgba(34,40,110,.72) calc(360deg - var(--cd, 0deg) + 4deg));
  box-shadow: inset 0 0 0 2px rgba(120,220,255,.55); }
.hud-slot.is-cooling .hud-slot-icon, .hud-slot.is-cooling > span:first-of-type { filter: grayscale(.85) brightness(.6); }
.hud-slot-cd-label { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  pointer-events: none; font: 800 18px/1 var(--font-mono, monospace); font-variant-numeric: tabular-nums;
  color: #ffe066; -webkit-text-stroke: 3px #1a1030; paint-order: stroke fill;
  text-shadow: 0 0 6px rgba(0,0,0,.95); }
@keyframes hud-cd-ready { 0% { box-shadow: 0 0 0 0 rgba(255,236,160,.95), inset 0 0 14px rgba(255,236,160,.9); }
  100% { box-shadow: 0 0 0 8px rgba(255,236,160,0), inset 0 0 0 rgba(255,236,160,0); } }
.hud-slot.is-cd-ready { animation: hud-cd-ready 450ms ease-out 1; }
@media (prefers-reduced-motion: reduce) { .hud-slot.is-cd-ready { animation: none; } }
.hud-slot-count { position: absolute; right: 3px; bottom: 1px; font-family: var(--font-mono);
  font-size: 11px; font-weight: 600; color: var(--ink); text-shadow: 0 1px 2px #000; }
/* AMMO ARTWORK SIZE. `object-fit: contain` fits the FILE, not the ink, and `arrow.png` is a 512²
   frame whose arrow occupies only 95×365 of it (18.6% of the width, 71.3% of the height — measured
   from the alpha channel). At the old 30px box that drew a 21px-tall, 5.6px-wide sliver inside a
   46px cell, next to neighbours whose 26px SVGs fill their own viewBox — which is exactly the
   "far too small/thin" complaint.
   The box is now 42px, the same near-full-cell inset the bag's tile uses (52px cell, 4px inset),
   which brings the arrow to ~30px of ink and gives it the same visual weight as slot 1. Sizing the
   BOX rather than cropping the PNG is what survives `node tools/icon-shots.mjs`: a tighter crop
   would be per-icon and the next re-render would silently undo it. */
/* THE ARROW IS PUT ON THE CELL'S DIAGONAL, and scaled past the box.
 *
 * `object-fit: contain` fits the FILE, not the ink, and the arrow's ink is 95x365 in a 512 frame —
 * 18.6% of the width. So even a 42px box inside a 46px cell drew a shaft under 8px wide, which is
 * why raising the box twice did not fix it: the box was never the binding constraint, the empty
 * corners of the PNG were.
 *
 * A square cell's diagonal is ~1.41x its side, so turning the arrow onto it buys length for free,
 * and the scale then spends that on thickness. Done here rather than by cropping the PNG because
 * icons are RENDERED from meshes by tools/icon-shots.mjs — a hand-crop is per-icon and the next
 * regeneration would silently undo it, which is the trap this file has fallen into before. */
.hud-slot--ammo .rpg-icon {
  /* NO ROTATE, NO SCALE — both were compensating for the ICON, in the wrong place.
     `arrow.png` is a near-vertical arrow with wide empty margins either side, so `object-fit:
     contain` fits it by HEIGHT and leaves it looking thin, which is what was reported. The answer
     was a 1.5 scale and a 42-degree turn, and that worked on an unbounded dark cell — on the plate
     it is 63px of content in a 40px box, so it spills the tile.
     The real fix is to re-render the icon so the arrow FILLS its frame diagonally (RO's own icons
     are drawn corner to corner for exactly this reason); until then it simply fits, which the plate
     now makes legible without the size hack. */
  width: 100%; height: 100%; object-fit: contain;
}
.hud-slot--ammo .hud-slot-icon { overflow: visible; }
/* An empty saddle is a PLACEHOLDER, not a state — it reads as "there could be something here",
   which is what greying it says and what a lit icon would not. */
.hud-slot--empty-mount { color: #6a6480; opacity: .72; }
/* AN EMPTY QUIVER IS NOT AN EMPTY SADDLE. The saddle cell greys out because nothing is wrong; this
   one is the reason a bow just did nothing, so it is lit rather than dimmed — a red-hot cell with a
   struck-through quiver and a red 0. Loud enough to find in peripheral vision, static enough to sit
   there for a walk back to town without nagging (the BLINK is what says "just now").
   The cell's border/background/shadow are INLINE styles (see `makeAmmoCell`), so the alarm's are
   written inline too by `setAmmo` rather than fought over with `!important` here — which would also
   have beaten the blink's own keyframes, since `!important` outranks an animation and inline does
   not. This rule owns only what is not inline. */
.hud-slot--ammo-empty { color: #ff7a6a; }
.hud-slot--ammo-empty .hud-slot-count { color: #ff9c8c; }
/* THE BLINK: you tried to shoot with nothing loaded. It pulses while you keep trying and stops
   about a second after you stop (AMMO_BLINK_MS in GameHUD.ts) — a permanent flash is edited out by
   the eye and would still be going while the player is doing something else entirely. */
@keyframes hud-ammo-alarm {
  0%, 100% { box-shadow: inset 0 1px 0 rgba(255,190,170,.18), 0 2px 5px rgba(0,0,0,.45); }
  50%      { box-shadow: 0 0 0 2px rgba(255,120,100,.95), 0 0 18px 4px rgba(255,90,70,.7);
             background: linear-gradient(180deg, rgba(168,44,40,.98), rgba(112,26,30,.98)); } }
/* INFINITE, bounded by the CLASS rather than by an iteration count: the gate is asked every frame
   while a target is held, and a version that restarted the animation on each attempt reset it to
   0% sixty times a second and so never reached the bright half of the cycle at all — measured in
   the live game, where the cell sat visibly still while "flashing". `blinkAmmo` therefore leaves a
   running animation alone and only pushes its end out, so the pulse continues while the player
   keeps trying and stops ~1.1s after they stop. */
.hud-slot.is-ammo-alarm { animation: hud-ammo-alarm 380ms ease-in-out infinite; }
/* LOW AMMO: one amber pulse per shot. `forwards` is deliberately absent — the animation must end
   on the cell's own amber, which `setAmmo` writes inline, so the pulse decays back into the state
   rather than leaving a brighter cell behind it after the last shot. */
@keyframes hud-ammo-low-pulse {
  0%   { box-shadow: inset 0 1px 0 rgba(255,226,170,.20), 0 2px 5px rgba(0,0,0,.45); }
  35%  { box-shadow: inset 0 1px 0 rgba(255,238,200,.55), 0 0 14px 3px rgba(232,170,52,.85); }
  100% { box-shadow: inset 0 1px 0 rgba(255,226,170,.20), 0 2px 5px rgba(0,0,0,.45); }
}
.hud-slot.is-ammo-low-pulse { animation: hud-ammo-low-pulse 300ms ease-out 1; }
@media (prefers-reduced-motion: reduce) { .hud-slot.is-ammo-low-pulse { animation: none; } }
@media (prefers-reduced-motion: reduce) { .hud-slot.is-ammo-alarm { animation: none;
  outline: 2px solid rgba(255,120,100,.95); outline-offset: 1px; } }
.hud-slot svg { display: block; filter: drop-shadow(0 1px 1px rgba(0,0,0,.6));
  position: relative; z-index: 1; }
/* The hotbar's inner rail comes from the PRIMARY tier rule above. */
/* Gems at the rail's four midpoints. A horizontal rail has no structure of its own, so these are
   what say where it begins and ends — the same divider motif as the panel titles and the logo. */
.hud-hotbar-gem { position: absolute; }
.hud-hotbar-gem--t { top: -6px; left: 50%; margin-left: -6px; }
.hud-hotbar-gem--b { bottom: -6px; left: 50%; margin-left: -6px; }
.hud-hotbar-gem--l { left: -6px; top: 50%; margin-top: -6px; }
.hud-hotbar-gem--r { right: -6px; top: 50%; margin-top: -6px; }

/* A hotbar cell is a SOCKET, not a swatch. Border colour, background and box-shadow are written
   inline by refreshToolbar/sit/mount, so the bevel here has to live somewhere those do not touch —
   hence ::after, an overlay that survives every state write and keeps the cut edge on all of them. */
.hud-slot { position: relative; width: 46px; height: 46px; border: 2px solid; border-radius: 7px;
  display: flex; align-items: center; justify-content: center; font-size: 26px;
  /* A CELL IS A DRAG SOURCE, so it must take pointer events at REST. The rail is click-through so
     a click near the bottom of the screen reaches the world; the cells opt back in because
     `dragstart` never fires on an element that cannot be pointed at, which is why reordering the
     bar and dropping a cell on the bin were both impossible. The rail's own padding stays
     click-through, so the world is still reachable between and around the cells. */
  pointer-events: auto; }
/* A CELL'S CONTENTS ARE NOT SEPARATE TARGETS. The artwork span, the keybind and the cooldown
   overlay are all children, so the pointer crossing onto one of them fires `dragleave` on the cell
   — which strobed the drop highlight on and off several times as a spell was dragged along the bar.
   The handler guards against it too (`relatedTarget`), and this makes the case not arise at all;
   both, because the guard is what survives a child being added later. */
.hud-slot > * { pointer-events: none; }
.hud-slot--ammo { pointer-events: auto; }
.hud-slot::after { content: ''; position: absolute; inset: 0; border-radius: 5px;
  pointer-events: none;
  /* BENEATH THE ARTWORK. This is the SOCKET — the lit lip and the shadowed floor of an empty
     hole — and a pseudo-element paints above the in-flow children unless it is told otherwise, so
     it was laying `rgba(0,0,0,.55)` across every icon on the bar. The same potion was visibly
     darker on the hotbar than in the bag, which was reported exactly that way. The socket is what
     the icon sits IN, not a filter over it. */
  z-index: 0;
  box-shadow:
    inset 0 1px 0 rgba(255,236,198,.20),            /* top lip, lit */
    inset 0 -2px 4px rgba(0,0,0,.55),               /* floor of the socket */
    inset 0 0 0 1px rgba(10,8,26,.75); }            /* the dark line that separates cell from rail */
/* AN ARMED SPELL. The cell pulses in the spell's own ember, so "the key did something" and "the
   next click will cast" are the same signal. Distinct from the boost cell's cyan glow, which is a
   state that is running rather than a mode that is waiting. */
.hud-slot.is-armed { border-color: #ff8a2b !important;
  box-shadow: 0 0 14px rgba(255,138,43,.85), inset 0 1px 0 rgba(255,216,138,.35) !important;
  animation: hud-armed-pulse 1.1s ease-in-out infinite; }
@keyframes hud-armed-pulse {
  0%, 100% { box-shadow: 0 0 10px rgba(255,138,43,.6), inset 0 1px 0 rgba(255,216,138,.3); }
  50%      { box-shadow: 0 0 18px rgba(255,138,43,1), inset 0 1px 0 rgba(255,216,138,.45); } }
@media (prefers-reduced-motion: reduce) { .hud-slot.is-armed { animation: none; } }
/* The keybind, top-left, as the plate has it. Small and quiet: it is a reminder for a hand that
   already knows the slot, not a label for someone reading the bar for the first time. */
.hud-slot-key { position: absolute; top: 1px; left: 3px; font-family: var(--font-mono);
  font-size: 10px; color: var(--ink-soft); text-shadow: 0 1px 1px #000; }

/* The crest above the rail — a gold hairline with a gem at its heart. */
.hud-hotbar-crest { position: absolute; left: 50%; bottom: 70px; transform: translateX(-50%);
  z-index: 60; pointer-events: none; display: flex; align-items: center; gap: 8px; }

