/* ═══════════════════════════════════════════════════════════════════════
   world-plate.css — THE PLAYER PLATE'S CSS, in one file (GH #2920, step 3b).

   The plate is a component (public/js/world-plate.js, markup in
   prototype/the-hall-3d/web/tpl-plate.html). Its rules used to sit in three
   sheets: the structure in world-shell.css (base), the majesty skin's look
   in world-skin.css (skin), and the Albion corner's arrangement in
   world-albion.css (corners). They are all here now, EACH STILL IN ITS
   LAYER and in its original order, so the cascade between them is
   unchanged: between layers the layer decides, within a layer the order
   below does. Moved mechanically on 2026-09-22 with the comments that
   introduced them; nothing was rewritten. The same three `.ws-plate`
   majesty blocks appear in the skin layer because three redesign passes
   left them there, each overriding the last by order; collapsing them is a
   separate pass with pixel diffs, not this file's job.

   This sheet loads LAST, after the three it came from, so within each layer
   these rules come after the rest of that layer. Proven by rect and
   computed-style probes of every part, Albion nav on and off, at 1920 and
   390, before and after the move.
   ═══════════════════════════════════════════════════════════════════════ */
@layer base, module, skin, nerm, corners;

@layer base {
/* ── the plate ───────────────────────────────────────────────────────
   One parchment object, not a stack of chips. Sized against the rail: the
   content box is --fx minus this file's padding, and everything inside is a
   whole multiple of the chrome pixel wherever it shows a pixel source. */

.ws-plate {
  flex: 0 0 auto;
  padding: 12px;
  background-image: var(--wc-parchment, linear-gradient(180deg, #cbb48f, #b39c76));
  background-size: var(--wc-parchment-tile, auto);
  color: var(--wc-ink-on-parchment, #33240f);
  border: 4px solid #33240f;
  box-shadow: 6px 6px 0 rgba(0, 0, 0, .55), inset 0 0 24px rgba(138, 112, 72, .35);
  image-rendering: pixelated;
}

/* THE PORTRAIT SIZE IS DECIDED IN SCRIPT, not here, and `--ws-bust` is where
   the answer arrives. It has to be a WHOLE MULTIPLE of the 112px pixel budget
   or the upscale is fractional, and CSS cannot round to a multiple of 112.
   world-shell.js's fitRail() picks from 336 / 224 / 112 / none against the
   MEASURED rail box, because the rail's width and height move in opposite
   directions as the window changes shape. See its header.

   The fallback is 224, which is what frame D resolves to anyway, so a page
   where the script has not run yet looks right rather than looking broken. */
.ws-nest {
  position: relative; /* the guild badge hangs in its corner */
  width: calc(var(--ws-bust, 224px) + 16px);
  max-width: 100%;
  margin: 0 auto 12px;
  padding: 4px;
  background: #241708;
  border: 4px solid #33240f;
  box-shadow: inset 3px 3px 0 rgba(0, 0, 0, .6);
}

/* the guild's coin, worn on the portrait (#2404) */
.ws-guildbadge {
  position: absolute;
  top: 6px; left: 6px;
  width: 34px; height: 34px;
  object-fit: cover;
  border: 3px solid #8a6d2f;
  background: #1a1008;
  box-shadow: 2px 2px 0 #000;
  z-index: 2;
}

.ws-guildbadge[hidden] { display: none; }

.ws-nest[hidden] { display: none; }

.ws-bust {
  display: block;
  width: var(--ws-bust, 224px);
  height: var(--ws-bust, 224px);
  /* The canvas backing store is set to the same number, and nine-portrait
     draws into it with smoothing off, so this is belt and braces against a
     browser that scales a canvas for a device pixel ratio. */
  image-rendering: pixelated;
}

/* ── compact: the plate turns sideways ───────────────────────────────
   Reached when even a 112px portrait cannot sit ABOVE the text and still
   leave room for six doors — a wide, short window, where the rail is broad
   and shallow. The picture goes beside the type instead of over it, which is
   the same shape variant C used, and the doors go to three columns so they
   need two rows instead of three. */

.ws-rail[data-plate="compact"] .ws-plate {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.ws-rail[data-plate="compact"] .ws-nest { margin: 0; flex: none; }

/* Everything that was centred under the portrait is now a left-aligned column
   beside it. `min-width: 0` so a long handle ellipsises instead of shoving the
   picture out of the plate. */
.ws-rail[data-plate="compact"] .ws-platetext {
  min-width: 0;
  flex: 1 1 auto;
}

.ws-rail[data-plate="compact"] .ws-name,
.ws-rail[data-plate="compact"] .ws-house,
.ws-rail[data-plate="compact"] .ws-level { text-align: left; }

.ws-rail[data-plate="compact"] .ws-name { font-size: 14px; }

.ws-rail[data-plate="compact"] .ws-house { margin-top: 6px; }

.ws-rail[data-plate="compact"] .ws-lives { margin-top: 6px; }

.ws-rail[data-plate="compact"] .ws-barrow { margin-top: 6px; }

.ws-name {
  font-family: var(--ws-head);
  /* Press Start 2P is enormous per character. 18px here is the mock's 9px at
     the 2x the rail's width asks for. */
  font-size: 18px;
  line-height: 1.4;
  text-align: center;
  overflow-wrap: anywhere;
}

.ws-house {
  font-family: var(--ws-head);
  font-size: 11px;
  line-height: 1.4;
  letter-spacing: .04em;
  text-align: center;
  color: #8a2f1f;
  margin-top: 10px;
}

.ws-house:empty { display: none; }

.ws-level {
  font-size: 24px;            /* VT323 is condensed and sits small */
  line-height: 1;
  text-align: center;
  color: rgba(51, 36, 15, .72);
  margin-top: 4px;
}

.ws-level:empty { display: none; }

/* Letterpress: dark ink on pale parchment wants a light lift under it, which
   is the opposite of the dark text-shadow the leather surfaces use. */
.ws-name, .ws-house, .ws-level, .ws-lives, .ws-tag {
  text-shadow: 2px 2px 0 rgba(255, 255, 255, .26);
}

/* ── the gathering skills (#2287 ruling 2) ─────────────────────────
   Three chips on the card — MINE, WOOD, FISH — each its track's level.
   Hidden until the endpoint answers with the flag on; see paintSkills.
   Letterpress ink like its neighbours, never a plate of its own: the card
   already has a frame, and chrome inside chrome is the mud (#2020). */

.ws-skills {
  display: flex;
  justify-content: center;
  gap: 10px;
  font-family: var(--ws-head);
  font-size: 10px;
  line-height: 1.4;
  letter-spacing: .03em;
  color: rgba(51, 36, 15, .72);
  margin-top: 8px;
  text-shadow: 2px 2px 0 rgba(255, 255, 255, .26);
}

.ws-skills[hidden] { display: none; }

/* one line per chip: the card column is narrow, and a label that wraps over
   its own number reads as two facts */
.ws-skill { white-space: nowrap; }

.ws-skill i {
  font-style: normal;
  color: #8a2f1f;
  margin-right: 3px;
}

/* a capped track earns the gold ink the rest of the chrome saves for wins */
.ws-skill-max, .ws-skill-max i { color: #8a6c2f; }

.ws-rail[data-plate="compact"] .ws-skills { justify-content: flex-start; margin-top: 6px; }

/* ── lives ─────────────────────────────────────────────────────────
   Hidden between runs. See paintLives in world-shell.js: lives are a RUN
   number, and the player-level column nothing ever writes would have shown
   every cat three of nine pips forever. */

.ws-lives {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--ws-head);
  font-size: 11px;
  line-height: 1.4;
  color: rgba(51, 36, 15, .72);
  margin-top: 10px;
}

.ws-lives[hidden] { display: none; }

.ws-pip {
  display: inline-block;
  width: 12px;
  height: 12px;
  background: #c49a3e;
  margin-right: 4px;
  box-shadow: inset -2px -2px 0 #8a6d2f;
}

.ws-pip.off { background: #8a7a5c; box-shadow: none; }

/* ── GP ────────────────────────────────────────────────────────────
   A label and a figure, and no bar (Wray, 2026-09-08). GP is unbounded and
   there is no "next rank at N" to fill toward, so the meter that used to sit
   here was drawn at a flat 100% for ever and read as a health bar. The row
   below is the whole readout now.

   `.ws-meter` further down is NOT dead: the bag's carry meter uses it and has
   a real ceiling. */

.ws-barrow { margin-top: 8px; }

.ws-barrow[hidden] { display: none; }

.ws-tag {
  display: flex;
  justify-content: space-between;
  font-family: var(--ws-head);
  font-size: 11px;
  line-height: 1.4;
  color: rgba(51, 36, 15, .72);
  margin-bottom: 5px;
}

/* ── THE WALLET (#3142) ────────────────────────────────────────────
   The Obol wallet, players.spendable_gp: the money a fee, a chest, a kill
   and the Bazaar move. Wray could not smoke a fee because nothing in the
   world showed it; the one figure here was `.ws-tag` above, labelled GP,
   which is players.seasonal_points, the arena season score that no Obol
   ever moves. So the wallet takes this row, label left and figure right as
   the season row had it, and the season row stands down in every skin but
   the v2 chips row, which says "Infamy N" (#3151) and so cannot pass for the
   wallet. The markup says "Obols" (the ruled name, 2026-09-11/13); the
   letterpress skins upper-case it like every other label here. */
.ws-obols {
  display: flex;
  justify-content: space-between;
  font-family: var(--ws-head);
  font-size: 11px;
  line-height: 1.4;
  color: rgba(51, 36, 15, .72);
  margin-bottom: 5px;
  text-shadow: 2px 2px 0 rgba(255, 255, 255, .26);
}

.ws-obols[hidden] { display: none; }

.ws-obols > i { font-style: normal; text-transform: uppercase; }

.ws-obols > b { font-weight: inherit; }

.ws-barrow > .ws-tag { display: none; }

/* ── THE XP BAR (#2020, 2026-09-08) ───────────────────────────────────
   Albion's top-left carries TWO thick bars, health over energy, and that pair
   is most of why its corner reads as STATUS where ours read as a label. This
   is the second bar, and it is XP toward the next level because that is the
   only persistent number on the plate with an honest ceiling to fill toward
   (`/api/levels` returns progress_percent; the world was fetching it and
   dropping it). ⛔NOT GP -- Wray dropped that bar the same morning, and for
   exactly this reason: no denominator, so it drew full for ever.

   The trough borrows the meter's own colours rather than inventing a bar, so
   it reads as a sibling of the lives row above it and not as a second idiom
   on one card. */
.ws-xp {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 4px 0 0;
}

.ws-xptrough {
  flex: 1 1 0;
  min-width: 0;
  height: 10px;
  border: 2px solid #33240f;
  background: #3c2c18;
  position: relative;
  image-rendering: pixelated;
  overflow: hidden;
}

.ws-xpfill {
  height: 100%;
  width: 0;
  background: repeating-linear-gradient(90deg, #6fa8c9 0 12px, #4d7c99 12px 16px);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, .22), inset 0 -2px 0 rgba(0, 0, 0, .3);
  transition: width 200ms linear;
}

/* AT THE CAP THE BAR IS A STATEMENT, NOT A PROMISE. A full bar that can never
   move is the thing the GP bar was killed for, so the capped one says MAX and
   changes colour rather than sitting at 100% pretending to be progress. */
.ws-xp.is-max .ws-xpfill {
  background: repeating-linear-gradient(90deg, #c49a3e 0 12px, #8a6d2f 12px 16px);
}

.ws-xplabel {
  flex: none;
  font-family: var(--sk-data, 'Press Start 2P', monospace);
  font-size: 7px;
  color: #9d8a6d;
  white-space: nowrap;
}

/* THE HUD PASS'S PARTS ARE OFF IN EVERY OTHER SKIN (#3069 S1). The energy
   bar, the XP chip and the buff row exist only in the v2 plate's design, so
   no v1 skin has a rule for them. `hidden` alone is not enough: a writer
   that ran with HUD v2 off, or HUD v2 without the Albion corner, would show
   them unstyled. Only the v2 corner rules at the end of this file turn them
   on. */
.ws-en,
.ws-eat,
.ws-xpchip,
.ws-buffs { display: none; }

/* THE TARGET PLATE'S PARTS, likewise (#3069 S2): the picture that is not a
   cat's portrait (a creature's icon, the paw), the X and the actions row
   exist only on the v2 target plate, and world-target-plate.css is the one
   sheet that shows them. */
.ws-pic,
.ws-close,
.ws-acts { display: none; }

}
/* end of @layer base */

@layer skin {
/* ── panels ─────────────────────────────────────────────────────────── */

body.skin-majesty .ws-plate {
  border-style: solid;
  border-image-repeat: repeat;
  image-rendering: pixelated;
  background: transparent;
  box-shadow: none;
  color: var(--sk-ink);
}

/* the plate is the player card: 16x16 art, corner 5, so 20px borders at x4 */
body.skin-majesty .ws-plate {
  border-image-source: url('/assets/ui/panel-plate.png?v=2026-08-29a');
  border-image-slice: 5 fill;
  border-image-width: 20px;
  border-width: 20px;
  /* A NINE-SLICE BORDER IS THE FRAME, NOT THE PADDING. Content lands flush on
     the inner edge and the last glyph column gets shaved by overflow. Every
     panel here carries its own padding on top of the border. */
  padding: 6px 10px;
}

/* ── the player card ────────────────────────────────────────────────── */

body.skin-majesty .ws-nest {
  /* NO WIDTH OR HEIGHT HERE. world-shell.js sizes the portrait itself, to one
     of BUST_STEPS (336/224/112) chosen for the rail it ended up with, and a
     hardcoded 104 put a 112px canvas 22px outside its own frame. The shell
     owns the size; the skin owns the surround.

     And the surround is the PANEL, not Cozy's portrait frame: that frame is a
     whole 64x64 image rather than a nine-patch (measured, its corner reads
     60 9 6 9, which is not sliceable), so it may only be shown at 64, 128 or
     192 and none of those wraps a 112 bust. A nine-patch takes whatever size
     the shell asks for and keeps its rim one pixel. */
  border-style: solid;
  border-image-repeat: repeat;
  border-image-source: url('/assets/ui/panel-well.png?v=2026-08-29a');
  border-image-slice: 4 fill;
  /* 8, NOT 16, and it is arithmetic rather than taste. fitRail() budgets the
     nest at `bust + 16` when it picks a portrait size, so a 16px border on
     each side takes 16 more than the shell allowed for, the plate grows, and
     the sixth door is pushed off the bottom of the rail. 8px is still a whole
     multiple of the 4px art (x2), just a thinner rim than the panels. */
  border-image-width: 8px;
  border-width: 8px;
  box-sizing: content-box;
  width: max-content;
  height: max-content;
  background: none;
  box-shadow: none;
  image-rendering: pixelated;
  padding: 0;
  overflow: visible;
}

body.skin-majesty .ws-bust {
  /* static, not absolute: the canvas is laid out by the shell, and taking it
     out of flow is what let it hang outside its own frame */
  position: static;
  image-rendering: pixelated;
  display: block;
}

/* THE TOME IS NOT A NAME FACE. Wray: "Special font for player name is not
   working, its too large to be legible so cant fold that font in there." A
   blackletter needs size to read and the plate has none to give, so the name
   goes back to the bitmap face and the tome keeps the places it earns —
   panel headings, window titles, and the single capital on a target. */
body.skin-majesty .ws-plate .ws-platetext .ws-name {
  font-family: var(--sk-head, 'Press Start 2P', monospace);
  font-size: 11px;
  letter-spacing: .04em;
  line-height: 1.05;
  /* a guest handle is 19 characters and ran to three lines at this size,
     pushing the doors down the rail. Two lines, then it is cut: the name is
     an identity, not a paragraph. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  letter-spacing: 0;
  color: #fff3dc;
  text-shadow: 0 2px 0 #000;
  text-transform: none;
}

body.skin-majesty .ws-house { color: var(--sk-hot); text-shadow: none; }

body.skin-majesty .ws-level { color: var(--sk-ink-dim); text-shadow: none; }

body.skin-majesty .ws-pip {
  background: #141a22;
  box-shadow: inset 0 0 0 2px #3b4553;
  border: 0;
}

body.skin-majesty .ws-pip[data-on='1'],
body.skin-majesty .ws-pip.on {
  background: var(--sk-hot);
  box-shadow: none;
}

/* ── the chat bar and the camera pad keep their shapes, take the palette ── */

body.skin-majesty .ws-barrow {
  color: var(--sk-ink);
}

/* ══════════════════════════════════════════════════════════════════════
   THE HERO CARD, REBUILT (#2020) — option B, picked 2026-08-30
   ──────────────────────────────────────────────────────────────────────
   Wray: "we need to reimagine that top left hero panel as that looks like
   it needs polish and love, fallen behind the rest ... one line then the
   numbers for the gear."

   What was wrong with it, so this is answering something rather than
   restyling: a portrait framed inside a plate is a frame inside a frame,
   which is exactly what every other window in this skin stopped doing;
   three centred lines is a lot of height for a handle, a house and a
   level; and the handle is a twenty-character guest id that dominated
   everything near it.

   So: the portrait sits ON the plate with no nest of its own, identity is
   one line, and the space that buys goes to the numbers.
   ══════════════════════════════════════════════════════════════════════ */

body.skin-majesty .ws-rail[data-edge='left'] .ws-plate {
  display: flex;
  /* WRAPS, so the panel can be a full-width child on its own line without
     restructuring the header markup world-shell.js owns and re-renders. */
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  /* THE GROUND, SHARED WITH THE PANEL. Wray, 2026-08-30: "get rid of the
     tear in the extension."

     On my window the two halves measured flush -- plate bottom 100, panel
     top 100 -- and on his there was a visible black band between them. The
     difference is the portrait: `fitRail` picks a bust of 336, 224 or 112
     depending on how much rail there is, so a taller screen grows the card
     and any rounding in the join grows with it. Chasing the pixel would have
     fixed one screen.

     Painting both halves on the same colour means a seam cannot show through
     to the rail whatever the arithmetic does, because there is nothing
     behind them to show. The nine-slice still draws the edges; this is only
     what is under it. */
  background-color: #1b2431;
  background-clip: padding-box;
}

/* NO NEST, AND A KNOWN SIZE.

   The portrait is a picture on the plate, not a picture in a frame on a
   plate -- the frame-inside-a-frame the windows were fixed for, still
   sitting in the corner.

   And it is pinned to 56px rather than left to `fitRail`, which sizes the
   bust 336 / 224 / 112 by how much rail there is. That is right for a rail
   whose card is the only thing in it and wrong now the card is the lid of a
   character panel: on a tall screen the portrait grew to fill space the
   slots need, which is why the same layout looked compact here and enormous
   on Wray's screen. A header should be the same header at every height. */
body.skin-majesty .ws-rail[data-edge='left'] .ws-nest {
  flex: 0 0 auto;
  border: 0;
  border-image: none;
  padding: 0;
  margin: 0;
  width: 56px;
  height: 56px;
  background: none;
  box-shadow: none;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-bust {
  width: 56px !important;
  height: 56px !important;
  object-fit: contain;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-platetext {
  /* `1 1 0`, NOT `1 1 auto`. The plate wraps now so the panel can be a
     full-width child, and flex decides whether to wrap from an item's BASE
     size -- which for `auto` is its content. A twenty-character handle set
     `white-space: nowrap` made that base enormous, so the text block wrapped
     onto its own line under the portrait and the header went from 96px to
     174. `min-width: 0` was already there and does not help: it allows
     shrinking after the wrapping decision, not before it. A basis of zero
     means it never asks for room it has not got. */
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
}

/* ONE LINE. The handle is a guest id most of the time, so it is allowed one
   line and then it stops -- it is not the most interesting thing about a
   cat and it was taking three lines' worth of attention. */
body.skin-majesty .ws-rail[data-edge='left'] .ws-name {
  font-size: 14px;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* HOUSE AND LEVEL ON ONE LINE. Two stacked lines for two short facts was
   most of the wasted height in the card; side by side they read as one
   subtitle, which is what they are.

   (The `.ws-platetext` restatement that used to sit here is gone: it set
   `flex-direction: column`, which the rule twenty lines above already sets,
   and two rules for one element is the pattern this file has been bitten by
   three times.) */
body.skin-majesty .ws-rail[data-edge='left'] .ws-house,
body.skin-majesty .ws-rail[data-edge='left'] .ws-level {
  display: inline-block;
  font-size: 13px;
  vertical-align: baseline;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-level {
  margin-left: 8px;
  color: var(--sk-gold-hi);
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-subline {
  display: flex;
  align-items: baseline;
  gap: 0;
  line-height: 1.2;
}

/* THE HEADER SHRINKS WHEN THE PANEL OPENS, and this is safe now in a way it
   was not before: the panel is a CHILD of the card, so changing the header's
   height cannot open a seam -- there is no join left to misalign. It was
   removed while the two were siblings for exactly that reason.

   The numbers: the rail is 530, the ribbon strip is 210, and the panel wants
   196. That leaves about 100 for a header that is 122 open. Halving the
   portrait and tightening the line gets it to ~70, which is what keeps all
   five ribbons clear of the tray. */
/* THE COMPACTION IS OBSOLETE, and it was the reason the open card looked
   poor: a 38px portrait in a 252px card is a postage stamp with dead space
   beside it.

   It earned its place once. The panel and the ribbon strip were competing for
   a rail budget computed from constants, and halving the portrait was what
   kept all five ribbons clear of the tray -- the comment above still cites
   the arithmetic it was solving ("the rail is 530, the strip is 210").

   That arithmetic is gone. `fit()` in world-equip.js now measures the room
   actually left and gives the panel exactly that, so a taller header costs
   the panel a few scrollable pixels rather than pushing a ribbon off the
   screen. The squeeze buys nothing now and costs the cat a third of its size.

   The name and house keep their full size for the same reason. */
body.skin-majesty .ws-plate.is-open .ws-name { font-size: 13px; }

/* ONE HEADER BAND WHEN OPEN, in both plate modes.
   ──────────────────────────────────────────────────────────────────────
   Open, in `tall`, the portrait sat alone on its own line with about 130px
   of empty card beside it and the name wrapped underneath -- which is what
   made the top half read as unfinished however big the portrait was. The
   cause is width, not intent: `.ws-platetext` takes the full content width,
   so 56 + 192 overflows 192 and the flex row wraps.

   Giving the text `flex: 1 1 0` lets it share the line and take whatever is
   left, which is the arrangement `[data-plate="compact"]` already uses. So
   this is not a new layout -- it is the existing one, applied in the state
   where the card has a body under it and the header needs to be a band
   rather than a column.

   `min-width: 0` so a long handle ellipsises instead of shoving the cat out
   of the card; `1 1 0` rather than `1 1 auto` because auto measures the
   content first and a long guest handle would decide it needs the whole
   line again. */
body.skin-majesty .ws-plate.is-open .ws-name,
body.skin-majesty .ws-plate.is-open .ws-house,
body.skin-majesty .ws-plate.is-open .ws-subline { text-align: left; }

/* THE CARD GIVES ROOM BACK WHEN IT OPENS. Wray: "probably that hero card
   needs rethinking now its going to extend into a character sheet too", and
   separately "the left ribbons shouldnt get pushed off screen when that part
   opens."

   Those are the same problem. The rail is 530 tall; a 180px card plus a
   210px ribbon strip leaves 140 for a panel that wants 200. Six slots
   instead of nine bought back a row, and the rest comes from the card: while
   you are looking at your slots you do not need a large portrait of the cat
   wearing them. It compacts to a single line and hands over about 70px,
   which is what makes everything fit. */
body.skin-majesty .ws-plate.is-open {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px;
}

/* THE PORTRAIT IS SIZED ONCE, in the rail rule above. This used to shrink it
   again on open, which meant the card changed size as you opened it and two
   rules described one element -- the pattern that has bitten this file three
   times now. It is 56px whether the panel is open or shut. */
body.skin-majesty .ws-plate.is-open .ws-platetext {
  /* `0`, NOT `auto`, AND THAT IS THE WHOLE HEADER FIX. With `auto` the flex
     base size is the text's own content width, so a long guest handle
     measures wider than the card, the row wraps, and the portrait ends up
     alone on a line with 130px of empty card beside it -- which is what made
     the open header read as unfinished at any portrait size. `0` makes the
     text take whatever is left beside the cat instead of asking for what it
     wants first.

     I wrote this fix a second time, twenty lines up, instead of editing here
     -- and the later rule won, so nothing changed. Fifth time in this file
     that two rules have described one element. Deleted rather than layered. */
  flex: 1 1 0;
  min-width: 0;
  font-size: 13px;
  line-height: 1.3;
}

body.skin-majesty .ws-plate.is-open .ws-level { display: none; }

/* ══════════════════════════════════════════════════════════════════════
   THE RAIL AS TABS (world-rail-tabs.js) — first cut of Wray's sketch
   ──────────────────────────────────────────────────────────────────────
   "a smaller hero card in the top left, then tabs as majesty ribbons
   vertical and then we have the rail space for that tab and also a window
   open space, the tabs can just use the icon instead of text too maybe."
   ══════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════════
   THE LEFT RAIL IS A COLUMN OF RIBBONS (#2020)
   ──────────────────────────────────────────────────────────────────────
   Wray, 2026-08-29: "Im convinced now we use ribbons as the nav on the side
   instead of back to buttons ... lets go back to horizontal ribbons with
   animations on selection. no ribbons used on any element are default
   orange, we are using the highlighted gold and red for none selected."

   WHAT WENT, AND WHY IT IS DELETED RATHER THAN DISABLED
   The beam, the hanging vertical banners and the in-rail panel are gone.
   The panel was the "info lives under the ribbons" idea he called wishful
   thinking; the banners were my misreading of "horizontal" as a row rather
   than as the ribbon's own shape. Leaving either behind a class nobody sets
   would leave two rail designs in one file for the next person to choose
   between.

   THE SHAPE
   tab-off.png / tab-on.png are Majesty's ribbon3 at native 44x12: a flat
   left end, a field, and a swallowtail notch cut into the right, with its
   own drop-shadow bar beneath. Sliced 0 5 0 4 it stretches to any width and
   any height while both ends stay drawn. At x3 the art's 12px becomes 36 —
   a whole multiple, so nothing shimmers.

   THE ANIMATION
   Selection extends the ribbon to the rail's full width and swaps red for
   gold. Stepped, not eased: a pixel ribbon that slides on a sub-pixel curve
   stops looking drawn. Width is the only thing that moves, so nothing
   reflows around it — the column's height never changes.
   ══════════════════════════════════════════════════════════════════════ */

body.skin-majesty .ws-rail.wrt-on .ws-lives,
body.skin-majesty .ws-rail.wrt-on .ws-barrow { display: none; }

/* ── THE PLATE IS A PREVIEW NOW (Wray, 2026-09-04: "we polish the top left
   little profile preview box"). It opens the Character window, so it dresses
   as a small card rather than a control panel: name in the tome face with
   the red cap like every other name in the skin, the house line quiet, the
   gathering chips tidied to one dim row, and a gold ring under the hand so
   it reads as a door. Nothing may leak past its frame -- the level chip was
   printing outside the plate's right edge.

   AT THE FILE'S FOOT ON PURPOSE: the plate's base styles live mid-file and
   these are their override -- equal specificity means order decides, and the
   first draft of this block sat EARLIER and silently lost the font. */
body.skin-majesty .ws-plate { overflow: hidden; }

body.skin-majesty .ws-rail[data-edge='left'] .ws-plate:hover,
body.skin-majesty .ws-rail[data-edge='left'] .ws-plate:focus-visible {
  border-image-source: url('/assets/ui/panel-lit.png?v=2026-08-29a');
  outline: none;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-name {
  font-family: var(--sk-tome);
  font-size: 19px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--sk-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-name::first-letter {
  color: var(--sk-hot);
  font-size: 1.25em;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-house {
  font-family: var(--sk-body, 'VT323', monospace);
  font-size: 16px;
  letter-spacing: .04em;
  color: var(--sk-hot);
  text-transform: capitalize;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-skills {
  display: flex;
  gap: 10px;
  font-family: var(--sk-body, 'VT323', monospace);
  font-size: 15px;
  color: var(--sk-ink-dim);
  letter-spacing: 0;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-skill {
  text-decoration: none;
  color: var(--sk-ink-dim);
}

/* ── THE PLATE, ROUND TWO (Wray, 2026-09-04): "the profile picture is tiny,
   the player name unreadable... overall that window needs an overhaul."
   The portrait becomes the plate's biggest thing (56 -> 88, the old size was
   pinned with !important which is why the first polish could not move it),
   the name gets a real size, and the gathering chips leave for the character
   window -- they were facts about ACTIVITIES on a card about IDENTITY. */
body.skin-majesty .ws-rail[data-edge='left'] .ws-bust {
  width: 88px !important;
  height: 88px !important;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-name { font-size: 24px; }

body.skin-majesty .ws-rail[data-edge='left'] .ws-subline {
  display: flex; gap: 8px; align-items: baseline;
  /* one line: "Level 1" was wrapping to a ragged second row in the narrow
     column beside the bigger bust */
  white-space: nowrap; overflow: hidden;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-level {
  font-family: var(--sk-body, 'VT323', monospace);
  font-size: 15px; color: var(--sk-ink-dim);
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-skills { display: none; }

/* ── HUD B, BUILT BIG (Wray, 2026-09-04, on the mocks): "Hud B may be the
   option if we can have a bigger picture there to show the skeletal reveal
   and we are not showing lives or HP there. since right now lives only
   related to the arena mode". So: the name rides the banner art, the bust
   fills the plate at 120px, and neither pips nor HP are drawn here -- HP
   goes wherever the rail conversation puts it, and the skeleton reveal
   waits only on Jack's under-layer asset (nine-portrait.js already takes
   `under:`). */
body.skin-majesty .ws-rail[data-edge='left'] .ws-plate {
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-name {
  width: calc(100% + 8px);
  background: url('/assets/ui/title-banner-red.png?v=2026-08-30b') 0 0 / 100% 100% no-repeat;
  image-rendering: pixelated;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 21px;
  padding: 0 16px 5px;
  text-align: center;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-name::first-letter { color: #e8d5a9; }

body.skin-majesty .ws-rail[data-edge='left'] .ws-bust {
  width: 120px !important;
  height: 120px !important;
}

/* THE STACKING ORDER IS BANNER / BUST / LINE, and the text wrapper cannot
   say that -- the name and subline live inside .ws-platetext while the bust
   is its sibling. display:contents dissolves the wrapper so all three become
   the plate's own flex children and `order` can arrange them; the first cut
   left the bust floating over the banner. */
body.skin-majesty .ws-rail[data-edge='left'] .ws-platetext { display: contents; }

body.skin-majesty .ws-rail[data-edge='left'] .ws-name {
  order: -2;
  /* block, not flex: a centred flex row clips a long handle at BOTH ends and
     the ellipsis never draws (seen: "5FT-B05B8909" starting mid-string) */
  display: block;
  line-height: 25px;
  text-align: center;
  width: calc(100% + 8px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  position: static;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-nest { order: 0; margin: 0 auto; }

body.skin-majesty .ws-rail[data-edge='left'] .ws-subline {
  order: 1;
  justify-content: center;
  /* the compact-plate rules positioned this against the wrapper that
     display:contents just dissolved; said explicitly or it collapses to 0x0 */
  position: static;
  width: 100%;
  gap: 8px;
}

body.skin-majesty .ws-rail[data-edge='left'] .ws-skills { order: 2; }

/* not constant across the whole game, so not on the HUD */
body.skin-majesty .ws-rail[data-edge='left'] .ws-lives { display: none; }

/* ── the plate scales with the rail, not a constant (Wray, 2026-09-05:
   "why is the profile top left is poor... its crazy small box" -- 120px was
   tuned on one letterbox step and is a stamp on the next). The bust takes
   most of whatever the rail gives. */
body.skin-majesty .ws-rail[data-edge='left'] .ws-bust {
  width: calc(100% - 48px) !important;
  max-width: 168px;
  height: auto !important;
  aspect-ratio: 1;
}

}
/* end of @layer skin */

@layer corners {
/* ══════════════════════════════════════════════════════════════════════
   THE HERO PLATE, COMPACT (Wray's pick C, 2026-09-06, from kit section 9)

   "HERO PLATE lets try C compact albion." No plate at all: a round portrait
   in a brass ring, the name and house on one line, the level as a chip in
   the corner, and the two meters the plate already carried -- the lives
   pips (shown in a run) and the GP bar -- as thin bars under the name. It
   floats on the picture the way Albion's does, and it is the only one of
   the three that a phone can share its top edge with.

   Nothing here is new DOM. buildPlate() in world-shell.js still builds the
   nest, the bust, the badge, the text column, the lives row and the GP row,
   and six code paths keep painting them; this file changes what they look
   like in this corner and nothing about what they are. */
/* ⭐ROUND TWO (#2557, Wray 2026-09-21): ALBION'S PLATE, PART FOR PART. The
   ring, then a parchment name band over a dark well of bars, the level as a
   coin under the ring. This reverses the 2026-09-06 "the picture is the
   ground" at Wray's own call ("the player top left section needs a frame
   around all the info that is stylised"). world-albion-nav.js shapePlate()
   makes the band and the well out of the nodes buildPlate() already builds;
   every rule below is for that arrangement. Chrome pixel is `--sk-btn-k`
   (2 at a 1920 window), the same one every plank in the corner uses. */
body.nav-albion .an-tl .ws-plate {
  --ws-bust: max(96px, calc(var(--sk-btn-k, 2) * 52px));
  --an-ring: max(3px, calc(var(--sk-btn-k, 2) * 2px));
  position: relative;
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 0;
  /* ⛔THE RING WAS CLIPPING ON AN INVISIBLE FRAME (Wray, 2026-09-22).
     world-skin.css gives `.ws-plate` `overflow: hidden` ("nothing may leak
     past its frame", for the old preview card), and the brass ring and its
     drop shadow are drawn OUTSIDE the nest's box as spread shadows -- so the
     plate's box cut them flat on the top and the left. Overflow is visible
     here, and the plate is padded by the ring's width so the shadow has
     room inside the box as well. */
  overflow: visible;
  padding: calc(var(--an-ring) + 2px) 0 4px calc(var(--an-ring) + 2px);
  box-sizing: border-box;
  /* ⭐AN EXPLICIT WIDTH, NOT `auto`. `.an-tl` is a flex column with
     `align-items: flex-start`, so an auto-width plate shrink-wraps -- and a
     shrink-to-fit box containing a `flex: 1 1 auto` child with `min-width: 0`
     resolves that child to ZERO. Measured on the first corner build. */
  width: clamp(330px, 24vw, 440px);
  /* the plate has no frame of its own: the band and the well are the frame */
  border: 0;
  border-image: none;
  background: none;
  box-shadow: none;
}

/* the portrait's column: the ring, and the level coin under it */
body.nav-albion .an-tl .an-idcol {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  position: relative;
  z-index: 2;
}

/* the portrait: a brass ring, round, the guild badge tucked at its foot */
/* Albion's ring is a dark iron band with a brass line outside it; drawn as a
   border plus a spread shadow so the guild badge can still hang in its corner */
body.nav-albion .an-tl .ws-nest {
  flex: none;
  margin: 0;
  padding: 0;
  width: var(--ws-bust);
  height: var(--ws-bust);
  box-sizing: border-box;
  border: calc(var(--an-ring) + 2px) solid #3a3f4a;
  border-image: none;
  border-radius: 50%;
  background: #0e0c14;
  box-shadow: 0 0 0 var(--an-ring) #caa982, 0 4px 0 var(--an-ring) rgba(0, 0, 0, .55),
    inset 0 0 0 2px #1a1d24;
  overflow: hidden;
}

body.nav-albion .an-tl .ws-bust { width: 100%; height: 100%; }

body.nav-albion .an-tl .ws-guildbadge {
  top: auto; left: auto; right: 2px; bottom: 2px;
  width: 26px; height: 26px;
  border-radius: 50%;
}

/* ⭐`1 1 0`, NOT `1 1 auto` -- a lesson world-skin.css already paid for at
   its own `.ws-platetext` rule, which this corner is not scoped by. With
   `auto`, a twenty-character handle makes the base enormous, the item never
   fits, and it collapses to zero width while its text overflows. */
body.nav-albion .an-tl .ws-platetext {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  text-align: left;
  /* the band and the well tuck under the ring's right edge, as Albion's do */
  margin-left: calc(-1 * var(--an-ring) - 18px);
  margin-top: 10px;
}

/* THE NAME BAND: parchment, the name in the head face, the house at its end.
   Dark ink on parchment, so no picture-shadow here; the band IS the ground. */
body.nav-albion .an-tl .an-band {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  padding: 7px 10px 7px 30px;
  background: linear-gradient(#e8d6ad, #d6b991);
  border: 2px solid #4a3a24;
  box-shadow: 0 2px 0 #000;
  position: relative;
  z-index: 1;
}

body.nav-albion .an-tl .ws-name {
  font-size: 13px;
  line-height: 1.2;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #2e2113;
  text-shadow: none;
  min-width: 0;
}

/* the subline has nothing left in it once the band and the coin take its
   two children; it stays in the DOM for the other skins */
body.nav-albion .an-tl .ws-subline { display: none; }

body.nav-albion .an-tl .ws-house {
  flex: none;
  font-size: 8px;
  margin: 0;
  color: #a4343a;
  text-shadow: none;
}

/* THE WELL: the bars, on the dark panel the journal wears */
body.nav-albion .an-tl .an-well {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 10px 8px 30px;
  margin-top: -2px;
  border-style: solid;
  border-image-repeat: repeat;
  border-image-source: url('/assets/ui/panel-well.png?v=2026-08-29a');
  border-image-slice: 4 fill;
  border-image-width: calc(4px * var(--sk-btn-k, 2));
  border-width: calc(4px * var(--sk-btn-k, 2));
  image-rendering: pixelated;
}

body.nav-albion .an-tl .an-well:empty { display: none; }

/* the lives row is hidden between runs by the shell and lives are discontinued
   on this plate (Wray, 2026-09-21); the tag keeps the corner's ink */
body.nav-albion .an-tl .ws-lives,
body.nav-albion .an-tl .ws-tag { text-shadow: 0 2px 0 #000; color: var(--an-ink); }

body.nav-albion .an-tl .ws-lives { display: none; }

/* THE HEALTH BAR: Albion's first bar, red, the numbers centred on it */
body.nav-albion .an-tl .ws-hp {
  position: relative;
  height: 22px;
  margin: 0;
}

body.nav-albion .an-tl .ws-hp[hidden] { display: none; }

body.nav-albion .an-tl .ws-hptrough {
  position: absolute;
  inset: 0;
  background: #141820;
  border: 2px solid #4a3a24;
  box-shadow: inset 0 2px 0 #000, 0 2px 0 #000;
  box-sizing: border-box;
  overflow: hidden;
}

body.nav-albion .an-tl .ws-hpfill {
  height: 100%;
  width: 0;
  background: linear-gradient(#e0564c, #c8362e 60%, #8f2320);
  transition: width 200ms linear;
}

body.nav-albion .an-tl .ws-hp.is-down .ws-hpfill { background: #3a1a18; }

body.nav-albion .an-tl .ws-hplabel {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--an-head);
  font-size: 10px;
  letter-spacing: 1px;
  color: #fff;
  text-shadow: 0 2px 0 #000;
}

/* THE LEVEL IS A CHIP, in the plate's top-right corner: the same nine-slice
   and the same scaled frame as every button (world-skin.css, "THE MAJESTY
   PLANK IS THE BUTTON"). */
/* ...round two: the chip sits UNDER THE RING, in the portrait's column, where
   Albion keeps its coin. Static, so the column's flex places it. */
body.nav-albion .an-tl .ws-level {
  position: static;
  margin: 0;
  font-family: var(--an-head);
  font-size: 8px;
  line-height: 1;
  color: var(--sk-ink, #e6c88a);
  text-align: center;
  border-style: solid;
  border-image-repeat: repeat;
  border-image-source: url('/assets/ui/btn-idle.png?v=2026-08-29a');
  border-image-slice: 4 5 5 5 fill;
  border-image-width: calc(4px * var(--sk-btn-k, 2)) calc(5px * var(--sk-btn-k, 2)) calc(5px * var(--sk-btn-k, 2)) calc(5px * var(--sk-btn-k, 2));
  border-width: calc(4px * var(--sk-btn-k, 2)) calc(5px * var(--sk-btn-k, 2)) calc(5px * var(--sk-btn-k, 2)) calc(5px * var(--sk-btn-k, 2));
  padding: 1px 2px 3px;
  image-rendering: pixelated;
  white-space: nowrap;
}

/* THE LIVES ROW keeps the pack's segmented bar (meter.png), which is exactly
   its player health bar, and loses its word because the pips say it.

   ⭐THE GP ROW HAS NO BAR (Wray, 2026-09-08: "Drop the GP bar but letes keep
   the number"). It was label + bar on one line and the bar was drawn full
   for ever, because GP has no ceiling. Beside a portrait and above a row of
   real pips that is a health bar by every read except the true one. Label
   and figure only now, so the row justifies its two ends the way a stat line
   should. The `.ws-meter` rules that sized the bar here are gone with it --
   `buildPlate` no longer builds one, so they matched nothing. */
body.nav-albion .an-tl .ws-lives { margin: 0; gap: 6px; font-size: 7px; }

body.nav-albion .an-tl .ws-pips { display: flex; gap: 2px; }

body.nav-albion .an-tl .ws-pip { width: 9px; height: 9px; margin: 0; }

body.nav-albion .an-tl .ws-barrow { margin: 0; display: flex; align-items: center; gap: 8px; }

body.nav-albion .an-tl .ws-barrow[hidden] { display: none; }

/* the GP line at the foot of the well: label left, figure right, 9px so the
   figure reads beside the bars rather than under them */
body.nav-albion .an-tl .ws-tag { margin: 0; flex: 1 1 0; justify-content: space-between; gap: 4px; font-size: 9px; }

/* the wallet (#3142) sits where the season line did, dressed as it was:
   world-albion.css gives `.ws-tag` a gold 7px label over corner ink */
body.nav-albion .an-tl .ws-obols {
  margin: 0;
  flex: 1 1 0;
  justify-content: space-between;
  gap: 4px;
  font-size: 9px;
  color: var(--an-ink);
  text-shadow: 0 2px 0 #000;
}

body.nav-albion .an-tl .ws-obols > i { color: var(--an-gold); font-size: 7px; }

@media (max-width: 560px) {
/* the coin column and the strip's phone sizes live in the phone block at
     the END of this file: they must come after the coin rules to win */
  /* still an EXPLICIT width -- `auto` is the shrink-wrap trap the desktop
     rule above describes, and a phone is where it would bite hardest */
  /* measured at 390: the plate at 48vw (187) reached x199 and the row of
     four starts at x184. 40vw is 156, which leaves 16px between them. */
  body.nav-albion .an-tl .ws-plate { width: clamp(150px, 44vw, 330px); --ws-bust: 64px; --an-ring: 2px; }

/* at 156 wide there is no corner to spare: the ring shrinks to 64, the
     band and the well tuck under it by less, and the bars go thinner */
  body.nav-albion .an-tl .ws-platetext { margin-left: -10px; margin-top: 4px; }

body.nav-albion .an-tl .an-band { padding: 5px 6px 5px 16px; }

body.nav-albion .an-tl .an-well { padding: 5px 6px 5px 16px; gap: 4px; }

body.nav-albion .an-tl .ws-name { font-size: 9px; }

/* measured at 390: the band is 109px and the house word took all of it,
     leaving the NAME at 0px wide. The name is the band's job; the house is
     one tap away on the Settings door's House tab. */
  body.nav-albion .an-tl .ws-house { display: none; }

/* the bar figures lose their tracking, or "100 / 100" wraps in an 87px well */
  body.nav-albion .an-tl .ws-hplabel, body.nav-albion .an-tl .ws-xplabel { letter-spacing: 0; white-space: nowrap; }

body.nav-albion .an-tl .ws-hp, body.nav-albion .an-tl .ws-xp { height: 16px; }

body.nav-albion .an-tl .ws-hplabel, body.nav-albion .an-tl .ws-xplabel { font-size: 7px; }

body.nav-albion .an-tl .ws-level { position: static; font-size: 7px; }

} /* end of @media (max-width: 560px) */
/* THE XP BAR IN THE CORNER (#2020). Same row rhythm as the lives and GP rows
   above it: no margin of its own, tight, and its label the same 7px the other
   readouts use. The bar is what gives the corner Albion's second thick line;
   without it the plate is a name and a number on sand. */
/* ...round two: the XP bar is Albion's SECOND bar until energy exists, so it
   takes the same thickness as the health bar above it, and its label rides
   inside the trough the way the health figure does */
body.nav-albion .an-tl .ws-xp { margin: 0; gap: 0; position: relative; height: 22px; }

body.nav-albion .an-tl .ws-xp[hidden] { display: none; }

body.nav-albion .an-tl .ws-xptrough {
  position: absolute;
  inset: 0;
  height: auto;
  border: 2px solid #4a3a24;
  background: #141820;
  box-shadow: inset 0 2px 0 #000, 0 2px 0 #000;
}

body.nav-albion .an-tl .ws-xpfill {
  background: linear-gradient(#5aa0e8, #2f78c4 60%, #1d4f88);
  box-shadow: none;
}

/* ⛔THE LABEL TAKES THE CORNER'S INK, NOT THE RAIL'S. `.ws-xplabel` is
   #9d8a6d, which is a muted grey-brown that reads fine in a dark rail and is
   very nearly the colour of SAND. Measured on the plaza: the figure was
   there and unreadable. Every other readout in this corner already answers
   this the same way -- ink plus a hard shadow, because the ground is a
   picture and not a panel. */
body.nav-albion .an-tl .ws-xplabel {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  letter-spacing: 1px;
  color: #fff;
  text-shadow: 0 2px 0 #000;
}

/* "310 / 500" says what the bar is only if the bar says what it counts */
body.nav-albion .an-tl .ws-xplabel::before { content: 'XP\00a0'; color: var(--an-gold); }

body.nav-albion .an-tl .ws-xp.is-max .ws-xplabel::before { content: ''; }

/* ══════════════════════════════════════════════════════════════════════
   THE HERO PLATE, VERSION 2 (#3069 S1; Wray ruled the v7 mock "build it",
   2026-09-24: kit B, slate, square frames). Every rule here starts at
   `body.nav-albion.hud-v2`, and `hud-v2` is only ever set by
   world-hud-v2.js (FEATURE_WORLD_HUD_V2, or ?hud=1), so with the flag off
   none of this matches and the plate above is the plate.

   Same nodes as round two (shapePlate's idcol, band and well), drawn in the
   mock's shape: a square gold portrait frame on a house-lit ground, the
   level in a gold shield, the house ruby under the frame, a slate name
   plate carrying the bars, the chips row, then the buff row under it all.

   ── ONE CHROME PIXEL ──────────────────────────────────────────────────
   Every rim and every piece is a whole number of art pixels times --hv-k
   (world-hud-v2.css: 2 at 1920x1080, 1 on a phone or a laptop under
   1440x810). So this plate is the mock at k 2, and draws at half that on a
   phone, where the mock drew its own phone plate at about the same scale.

   ── THE PORTRAIT IS A WHOLE MULTIPLE OF THE 112px BUST ─────────────────
   NinePortrait composes the bust at 112 into a canvas whose backing store
   is the template's 224 until the rail's fit says otherwise. ⛔THE RAIL'S
   FIT STILL RUNS UNDER ALBION: world-shell.js applyFit measures the (empty)
   left rail and tells the plate 'fit', which sets the canvas to 112 at 1920
   and HIDES THE NEST when the rail picks size 0 (600 to 820px wide, iPad
   portrait). This plate sizes its own well, so the nest is shown whatever
   the fit said (the .ws-nest rule below). The mock's 96px well would be a
   fractional scale and smear the pixel art, so the well is 56 at k 1, 112
   at k 2 and 3, and 224 at k 4 (168 at k 3 would be 1.5x; 224 there drew
   the frame a third taller than the name plate, measured at 2560x1440).
   The frame is the well plus slate-equip.png's rim of 7 art pixels on each
   side.

   ── AT k 3 THE PLATE DRAWS AT k 2 ─────────────────────────────────────
   With the well held at 112, k 3's shield (72px) and ruby (54px) met under
   a 154px frame and the shield covered the ruby's left rim (2400x1350 and
   up, so every 2560x1440 screen). world-hud-v2.css allows a local --hv-k,
   so the plate takes 2 there and is the 1920 plate, part for part; k 4
   restores 4 with its 224 well, where the parts clear again.

   ── THE BARS ARE PIXEL-CLEAN, NOT THE MOCK'S HEIGHTS ──────────────────
   The mock squashed hpfill's 9 rows into 8px. Here health (and energy) are
   the trough's own 15 rows with the fill's 9 at k, 30px at 1920, and the
   XP bar is 9 rows with a 3-row fill showing xpfill.png's rows 2 to 4 (one
   light, two shade), so every row is still one art pixel. With energy
   hidden, health plus XP is about the height the mock's three bars took.
   ══════════════════════════════════════════════════════════════════════ */
body.nav-albion.hud-v2 .an-tl .ws-plate {
  --pv-bust: 56px;          /* the portrait well: 56, 112 or 224, never between */
  --pv-body: 178;           /* the name plate's width, in art pixels */
  --pv-paw: 3;              /* the paw glyph's art pixel (12x11), a sixteenth of the well */
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0;
  box-sizing: border-box;
  /* explicit, for the shrink-wrap reason round two's rule gives: the frame,
     then the body tucked 5 art pixels under it */
  width: calc(var(--pv-bust) + (14 + var(--pv-body) - 5) * var(--hv-k) * 1px);
  /* two art pixels of air above the frame: on a phone the plate hangs
     straight under the door row, and round two's ring padding is gone */
  padding: calc(2 * var(--hv-k) * 1px) 0 0;
  overflow: visible;
  border: 0;
  border-image: none;
  background: none;
  box-shadow: none;
  /* ⭐THE PLATE'S BOX IS NOT ITS HIT AREA (#3069 S1 review). Its rectangle
     spans the frame, the name plate, the gap under them and the full width
     of the buff row, and every press on that empty space was the plate's:
     it opened your Inventory, and a tap on the world beside a buff never
     walked. Only the frame, the name plate and each buff take a press. */
  pointer-events: none;
}

body.nav-albion.hud-v2 .an-tl .an-idcol,
body.nav-albion.hud-v2 .an-tl .ws-platetext,
body.nav-albion.hud-v2 .an-tl .ws-buff { pointer-events: auto; }

/* ⭐FULL SCALE FROM A 1280x700 LAPTOP (#3069 S10, audit HD-01 / C5). Under
   1440x810 the page's --hv-k is 1, and the plate drew at half the mock (a
   70px well, 7px labels, no house word) beside an action bar, a tracker and
   a minimap that keep their 1920 sizes: on the commonest laptops the piece
   Wray called cheap was the smallest thing on screen. So the plate takes its
   OWN k 2 from 1280x700, as the tracker does, and is the 1920 plate there,
   part for part. It fits: at 1280 the plate (486) and the target (362) end
   near x 870, left of the door row. The chat keeps k 1: the action bar's
   --ab-clear-l of 348 assumes it. */
@media (min-width: 1280px) and (min-height: 700px) {
  body.nav-albion.hud-v2 .an-tl .ws-plate { --pv-bust: 112px; --hv-k: 2; --pv-paw: 6; }
}

@media (min-width: 2400px) and (min-height: 1350px) {
  body.nav-albion.hud-v2 .an-tl .ws-plate { --hv-k: 2; }
}

@media (min-width: 3360px) and (min-height: 1890px) {
  body.nav-albion.hud-v2 .an-tl .ws-plate { --pv-bust: 224px; --hv-k: 4; --pv-paw: 12; }
}

body.nav-albion.hud-v2 .an-tl .an-idcol { position: relative; z-index: 2; gap: 0; }

/* the square frame: slate-equip.png, rim 8, at the chrome pixel. Shown
   even when the rail's fit hid it (see the header): the well is this
   plate's to size. */
body.nav-albion.hud-v2 .an-tl .ws-nest,
body.nav-albion.hud-v2 .an-tl .ws-nest[hidden] {
  display: block;
  position: relative;
  box-sizing: border-box;
  width: calc(var(--pv-bust) + 14 * var(--hv-k) * 1px);
  height: calc(var(--pv-bust) + 14 * var(--hv-k) * 1px);
  margin: 0;
  padding: 0;
  border-style: solid;
  border-width: 0;
  border-radius: 0;
  border-image: url('/assets/ui/kitb/slate-equip.png?v=2026-09-24a') 8 fill / calc(8 * var(--hv-k) * 1px) stretch;
  background: none;
  box-shadow: none;
  overflow: visible;
  image-rendering: pixelated;
}

/* the bust on the house's lit ground, inset to the frame's inner edge */
body.nav-albion.hud-v2 .an-tl .ws-bust {
  position: absolute;
  left: calc(7 * var(--hv-k) * 1px);
  top: calc(7 * var(--hv-k) * 1px);
  width: var(--pv-bust);
  height: var(--pv-bust);
  background: radial-gradient(circle at 50% 70%,
    color-mix(in srgb, var(--house, var(--hv-dim)) 70%, transparent) 0%,
    color-mix(in srgb, var(--house, var(--hv-dim)) 45%, #1a0f10) 38%,
    #120d12 78%);
  image-rendering: pixelated;
}

/* the base layer draws the canvas as a block, which beats [hidden]: the
   paw below hides it until a portrait exists */
body.nav-albion.hud-v2 .an-tl .ws-bust[hidden] { display: none; }

/* ⭐THE PAW, NEVER AN EMPTY WELL (#3069 S10, audit HD-03). Until your
   portrait is composed (or drawn from the last visit's copy) the frame holds
   the paw the target plate gives a cat with no portrait: the 12x11 glyph on
   the house's lit ground, every art pixel on a whole pixel at --pv-paw.
   world-plate.js sets data-pic="paw" for a hero plate under the pass only.
   The target plate's own rule (world-target-plate.css) is more specific and
   sizes its smaller paw by --tp-paw. */
body.nav-albion.hud-v2 .an-tl .ws-nest[data-pic='paw']::before {
  content: '';
  position: absolute;
  left: calc(7 * var(--hv-k) * 1px);
  top: calc(7 * var(--hv-k) * 1px);
  width: var(--pv-bust);
  height: var(--pv-bust);
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 11' shape-rendering='crispEdges'%3E%3Cpath fill='%23e7c77f' d='M3 0h2v3H3zM7 0h2v3H7zM0 3h2v3H0zM10 3h2v3h-2zM4 5h4v1H4zM3 6h6v1H3zM2 7h8v2H2zM3 9h6v1H3zM4 10h4v1H4z'/%3E%3C/svg%3E")
      center / calc(12 * var(--pv-paw) * 1px) calc(11 * var(--pv-paw) * 1px) no-repeat,
    radial-gradient(circle at 50% 70%,
      color-mix(in srgb, var(--house, var(--hv-dim)) 70%, transparent) 0%,
      color-mix(in srgb, var(--house, var(--hv-dim)) 45%, #1a0f10) 38%,
      #120d12 78%);
  image-rendering: pixelated;
  pointer-events: none;
}

/* the house ruby, hung on the frame's bottom rim (g-sock1.png, 18x20): its
   top at the well's foot, so it hangs 6 art pixels below the frame. Centred
   by auto margins, and placed from the top: the corner test forbids the
   left-50%-then-bottom shape that a fixed bottom-centre bar would use. */
body.nav-albion.hud-v2 .an-tl .ws-nest::after {
  content: '';
  position: absolute;
  z-index: 3;
  left: 0;
  right: 0;
  top: var(--pv-bust);
  width: calc(18 * var(--hv-k) * 1px);
  height: calc(20 * var(--hv-k) * 1px);
  margin: 0 auto;
  background: url('/assets/ui/kitb/g-sock1.png?v=2026-09-24a') 0 0 / 100% 100% no-repeat;
  image-rendering: pixelated;
  pointer-events: none;
}

/* the guild coin keeps a corner: top right, on the rim, gold-edged */
body.nav-albion.hud-v2 .an-tl .ws-guildbadge {
  top: calc(-3 * var(--hv-k) * 1px);
  right: calc(-3 * var(--hv-k) * 1px);
  left: auto;
  bottom: auto;
  width: calc(12 * var(--hv-k) * 1px);
  height: calc(12 * var(--hv-k) * 1px);
  border: calc(var(--hv-k) * 1px) solid var(--hv-gold);
  border-radius: 0;
  box-shadow: 0 0 0 calc(var(--hv-k) * 1px) var(--hv-black);
  z-index: 4;
}

/* the level in the gold shield (shield.png, 24x29), over the frame's corner.
   The text stays "Level N" for every other reader; the shield prints the
   number from data-n. */
body.nav-albion.hud-v2 .an-tl .ws-level {
  position: absolute;
  z-index: 4;
  left: calc(-1 * var(--hv-k) * 1px);
  bottom: calc(-7 * var(--hv-k) * 1px);
  box-sizing: border-box;
  width: calc(24 * var(--hv-k) * 1px);
  height: calc(29 * var(--hv-k) * 1px);
  margin: 0;
  padding: 0 0 calc(5 * var(--hv-k) * 1px);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-image: none;
  background: url('/assets/ui/kitb/shield.png?v=2026-09-24a') 0 0 / 100% 100% no-repeat;
  font-size: 0;
  line-height: 1;
  color: #2a1c0c;
  text-shadow: none;
  image-rendering: pixelated;
}

/* ⭐DRAWN, NOT READ TWICE (#3069 S10, audit C20). The shield's number, the
   name as typed, "Season" and the trailing GP are CSS content over text a
   screen reader already reads ("Level 1", the handle, the GP figure), and
   Chrome reads generated content too: "Level 1 1". The `/ ''` alt text
   keeps the pixels and silences the copy; the first declaration stands in
   a browser that does not know the alt syntax. "Season" is the one kept
   aloud, as its own alt, because nothing else says it. */
body.nav-albion.hud-v2 .an-tl .ws-level::after {
  content: attr(data-n);
  content: attr(data-n) / '';
  font-family: var(--hv-f-px);
  font-size: calc((4 * var(--hv-k) + 4) * 1px);
  color: #2a1c0c;
}

body.nav-albion.hud-v2 .an-tl .ws-level:empty { display: none; }

/* THE NAME PLATE: plate.png (rim 6 10 6 10), tucked under the frame */
body.nav-albion.hud-v2 .an-tl .ws-platetext {
  flex: none;
  position: relative;
  z-index: 1;
  box-sizing: border-box;
  width: calc(var(--pv-body) * var(--hv-k) * 1px);
  min-width: 0;
  margin: calc(5 * var(--hv-k) * 1px) 0 0 calc(-5 * var(--hv-k) * 1px);
  padding: calc(5 * var(--hv-k) * 1px) calc(8 * var(--hv-k) * 1px) calc(6 * var(--hv-k) * 1px) calc(11 * var(--hv-k) * 1px);
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--hv-k) * 1px);
  border-style: solid;
  border-width: 0;
  border-image: url('/assets/ui/kitb/plate.png?v=2026-09-24a') 6 10 6 10 fill /
    calc(6 * var(--hv-k) * 1px) calc(10 * var(--hv-k) * 1px) calc(6 * var(--hv-k) * 1px) calc(10 * var(--hv-k) * 1px) stretch;
  background: none;
  image-rendering: pixelated;
}

/* the name and the house on one line, no parchment band.
   ⭐THE HOUSE GIVES WAY FIRST, WHOLE. At k 1 the house word is 67px of Press
   Start 2P (monospace, so the mock's mixed case is no narrower) and it cut a
   guest's handle to "guest-154..." (#3069 S1 review). The handle is who you
   are, and the house is already the frame's lit ground and the ruby, so the
   band wraps and shows ONE line: a house that does not fit beside the name
   drops to the hidden second line, whole, rather than shrinking to a lone
   letter (which is what a shrink-first flex rule drew at 768 wide). The
   line is the name's own height (VT323 at 10k + 10, line-height 1), and the
   row gap is 8 art pixels so the house's 4-pixel lift (below) cannot poke
   the tops of its letters back over the clip from the second line. */
body.nav-albion.hud-v2 .an-tl .an-band {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: flex-start;
  gap: calc(8 * var(--hv-k) * 1px) calc(5 * var(--hv-k) * 1px);
  min-width: 0;
  max-height: calc((10 * var(--hv-k) + 10) * 1px);
  overflow: hidden;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  box-shadow: none;
}

/* The handle as typed (data-raw), in VT323: the painter keeps the text
   upper-case for every other skin, so the text is zero-size and the
   pseudo-element carries the name. An inline-block, so it can ellipsise in
   its own font and still gives the line a baseline to sit the house on. */
body.nav-albion.hud-v2 .an-tl .ws-name {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  font-size: 0;
  line-height: 1;
  color: var(--hv-ink);
  text-shadow: none;
}

body.nav-albion.hud-v2 .an-tl .ws-name::after {
  content: attr(data-raw);
  content: attr(data-raw) / '';
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: baseline;
  font-family: var(--hv-f-vt);
  font-size: calc((10 * var(--hv-k) + 10) * 1px);
  line-height: 1;
  letter-spacing: .01em;
  color: var(--hv-ink);
}

/* the house in its own colour, lifted toward white so every house reads on
   the plate's slate. ⭐44%, NOT A QUARTER (#3069 S15, K8): at 25% Smoulders
   measured 4.44:1 and Nighthollow 3.09:1 on the plate. 44% is the lowest
   whole mix at which all nine clear 4.5:1 against the LIGHTEST pixel of
   the plate's fill (worldHudV2S15.test.js reads the art and the palette and
   holds both ends). Written as the mock writes it ("Smoulders"):
   the shell hands every skin the upper-case label, so the case is set here.
   Whole or not at all: see the band above. */
body.nav-albion.hud-v2 .an-tl .ws-house {
  flex: none;
  white-space: nowrap;
  text-transform: lowercase;
  margin: 0;
  /* the name's inline-block puts the line's baseline at its FOOT (an
     overflow-hidden inline-block has no text baseline), about a quarter of
     VT323's size below the letters: lift the house word back onto them */
  position: relative;
  top: calc(-4 * var(--hv-k) * 1px);
  font-family: var(--hv-f-px);
  font-size: calc((2 * var(--hv-k) + 5) * 1px);
  letter-spacing: .06em;
  color: color-mix(in srgb, var(--house, var(--hv-dim)), #fff 44%);
  text-shadow: none;
}

body.nav-albion.hud-v2 .an-tl .ws-house::first-letter { text-transform: uppercase; }

/* the well is no longer a frame: the name plate is */
body.nav-albion.hud-v2 .an-tl .an-well {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--hv-k) * 1px);
  margin: 0;
  padding: 0;
  border-width: 0;
  border-image: none;
  background: none;
}

/* HEALTH and ENERGY: trough.png (15 rows, rim 4) with the segmented fill
   (9 rows) inset 3, the way world-hud-v2.css's .hv-bar draws it. The fill's
   width is the painter's percentage of the trough's content box. */
body.nav-albion.hud-v2 .an-tl .ws-hp,
body.nav-albion.hud-v2 .an-tl .ws-en {
  display: block;
  position: relative;
  height: calc(15 * var(--hv-k) * 1px);
  margin: 0;
}

body.nav-albion.hud-v2 .an-tl .ws-hp[hidden],
body.nav-albion.hud-v2 .an-tl .ws-en[hidden] { display: none; }

body.nav-albion.hud-v2 .an-tl .ws-hptrough,
body.nav-albion.hud-v2 .an-tl .ws-entrough,
body.nav-albion.hud-v2 .an-tl .ws-xptrough {
  position: absolute;
  inset: 0;
  height: auto;
  box-sizing: border-box;
  padding: calc(3 * var(--hv-k) * 1px);
  overflow: hidden;
  border-style: solid;
  border-width: 0;
  border-image: url('/assets/ui/kitb/trough.png?v=2026-09-24a') 4 fill / calc(4 * var(--hv-k) * 1px) stretch;
  background: none;
  box-shadow: none;
  image-rendering: pixelated;
}

/* ⭐NO SEAM (#3069 S10, audit HD-07 / C9). hpfill.png is 117 art pixels of
   uneven segments (7 and 8 wide) ending in a 2px sliver, and repeated it
   made one wide, notched segment about three quarters along the bar. So
   the fill is two pieces cut from it (kitb/README.md): the rounded left cap
   once, and one even segment (8 pixels and its 1-pixel divider) repeated
   from the left edge, so every segment is the same width and the cap covers
   the first tile exactly. */
body.nav-albion.hud-v2 .an-tl .ws-hpfill,
body.nav-albion.hud-v2 .an-tl .ws-enfill {
  height: 100%;
  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;
  box-shadow: none;
  image-rendering: pixelated;
  transition: width 200ms linear;
}

body.nav-albion.hud-v2 .an-tl .ws-enfill {
  width: 0;
  background-image: url('/assets/ui/kitb/encap.png?v=2026-09-25a'), url('/assets/ui/kitb/enseg.png?v=2026-09-25a');
}

/* the bar's width follows the pool in a fifth of a second: motion, so none
   for a player who asked for less */
@media (prefers-reduced-motion: reduce) {
  body.nav-albion.hud-v2 .an-tl .ws-hpfill,
  body.nav-albion.hud-v2 .an-tl .ws-enfill { transition: none; }
}

/* at zero the fill is zero wide anyway; round two's dark fill is not ours */
body.nav-albion.hud-v2 .an-tl .ws-hp.is-down .ws-hpfill { background: none; }

body.nav-albion.hud-v2 .an-tl .ws-hplabel,
body.nav-albion.hud-v2 .an-tl .ws-enlabel {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--hv-f-px);
  font-size: calc((3 * var(--hv-k) + 4) * 1px);
  letter-spacing: 0;
  white-space: nowrap;
  color: #fff4e0;
  text-shadow: 0 calc(var(--hv-k) * 1px) 0 #000;
}

/* ⭐EATING (#3619; Wray's EATING-A, 2026-10-03): the meal under health, in
   the health bar's trough, an amber fill the plate's painter runs on one
   transition over the channel the server timed, the meal's icon at its left
   and EATING <MEAL> across it. Only while a meal is being eaten. */
body.nav-albion.hud-v2 .an-tl .ws-eat {
  display: block;
  position: relative;
  height: calc(15 * var(--hv-k) * 1px);
  margin: 0;
}
body.nav-albion.hud-v2 .an-tl .ws-eat[hidden] { display: none; }
body.nav-albion.hud-v2 .an-tl .ws-eattrough {
  position: absolute;
  inset: 0;
  box-sizing: border-box;
  padding: calc(3 * var(--hv-k) * 1px);
  overflow: hidden;
  border-style: solid;
  border-width: 0;
  border-image: url('/assets/ui/kitb/trough.png?v=2026-09-24a') 4 fill / calc(4 * var(--hv-k) * 1px) stretch;
  image-rendering: pixelated;
}
body.nav-albion.hud-v2 .an-tl .ws-eatfill {
  width: 0;
  height: 100%;
  background: linear-gradient(#f0c06a, #c07a2c);
  box-shadow: inset 0 calc(-2 * var(--hv-k) * 1px) 0 rgba(0, 0, 0, .25);
}
body.nav-albion.hud-v2 .an-tl .ws-eatic {
  position: absolute;
  left: calc(4 * var(--hv-k) * 1px);
  top: 50%;
  width: calc(11 * var(--hv-k) * 1px);
  height: calc(11 * var(--hv-k) * 1px);
  transform: translateY(-50%);
  background-repeat: no-repeat;
  image-rendering: pixelated;
}
body.nav-albion.hud-v2 .an-tl .ws-eatlabel {
  position: absolute;
  inset: 0 0 0 calc(17 * var(--hv-k) * 1px);
  display: flex;
  align-items: center;
  font-family: var(--hv-f-px);
  font-size: calc((3 * var(--hv-k) + 3) * 1px);
  white-space: nowrap;
  overflow: hidden;
  color: #fff4e0;
  text-shadow: 0 calc(var(--hv-k) * 1px) 0 #000;
}
/* the food buff is pixel art, not a painted card face (#3619) */
body.nav-albion.hud-v2 .an-tl .ws-buff.is-px .ws-buffic { image-rendering: pixelated; }
@media (prefers-reduced-motion: reduce) {
  body.nav-albion.hud-v2 .an-tl .ws-eatfill { transition: none !important; }
}

/* XP: the thin LINE, not a second bar (#3069 S10, audit HD-18). At 9 rows
   with the health trough's rims, 0 XP read as an empty mana bar under the
   health. It is 5 art rows now (10px at k 2): a black top and sides, three
   rows of fill showing xpfill.png's rows 2 to 4 at one art pixel each, and
   a gold baseline, so no XP reads as a thin gold line waiting to fill. Its
   figure is on the chips row. */
body.nav-albion.hud-v2 .an-tl .ws-xp {
  display: block;
  position: relative;
  height: calc(5 * var(--hv-k) * 1px);
  margin: 0;
}

body.nav-albion.hud-v2 .an-tl .ws-xp .ws-xptrough {
  padding: calc(var(--hv-k) * 1px) calc(var(--hv-k) * 1px) calc(var(--hv-k) * 1px);
  border-image: none;
  background:
    linear-gradient(var(--hv-gold), var(--hv-gold)) left bottom / 100% calc(var(--hv-k) * 1px) no-repeat,
    var(--hv-well);
  box-shadow:
    inset 0 calc(var(--hv-k) * 1px) 0 var(--hv-black),
    inset calc(var(--hv-k) * 1px) 0 0 var(--hv-black),
    inset calc(-1 * var(--hv-k) * 1px) 0 0 var(--hv-black);
}

body.nav-albion.hud-v2 .an-tl .ws-xp[hidden] { display: none; }

body.nav-albion.hud-v2 .an-tl .ws-xpfill,
body.nav-albion.hud-v2 .an-tl .ws-xp.is-max .ws-xpfill {
  height: 100%;
  background: url('/assets/ui/kitb/xpfill.png?v=2026-09-24a') 0 calc(-2 * var(--hv-k) * 1px) / 100% calc(6 * var(--hv-k) * 1px) no-repeat;
  box-shadow: none;
  image-rendering: pixelated;
}

body.nav-albion.hud-v2 .an-tl .ws-xplabel { display: none; }

/* THE CHIPS ROW: "XP 180 / 400", "Obols 1,240" and "Infamy 1,240". The last
   figure is players.seasonal_points (world-shell.js loadStats), the season
   score, and its ruled name is Infamy (#3151, NAMES 1A, 2026-09-26). It read
   "Season N GP" until then; the label is the markup's own word now, first,
   the way the XP and Obols chips put theirs. */
body.nav-albion.hud-v2 .an-tl .ws-barrow {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: calc(6 * var(--hv-k) * 1px);
  row-gap: calc(2 * var(--hv-k) * 1px);
  margin: calc(1 * var(--hv-k) * 1px) 0 0;
  font-family: var(--hv-f-px);
  font-size: calc((2 * var(--hv-k) + 5) * 1px);
  line-height: 1.2;
  white-space: nowrap;
  color: var(--hv-dim);
  text-shadow: none;
}

body.nav-albion.hud-v2 .an-tl .ws-barrow[hidden] { display: none; }

body.nav-albion.hud-v2 .an-tl .ws-xpchip { display: inline; }

body.nav-albion.hud-v2 .an-tl .ws-xpchip[hidden] { display: none; }

body.nav-albion.hud-v2 .an-tl .ws-xpchip i { font-style: normal; color: var(--hv-dim); }

body.nav-albion.hud-v2 .an-tl .ws-xpchip b { font-weight: 400; color: var(--hv-ink); }

body.nav-albion.hud-v2 .an-tl .ws-tag {
  flex: none;
  display: inline-flex;
  align-items: baseline;
  justify-content: flex-start;
  gap: calc(3 * var(--hv-k) * 1px);
  margin: 0;
  font-size: inherit;
  text-shadow: none;
}

body.nav-albion.hud-v2 .an-tl .ws-tag > :first-child { font-size: inherit; color: var(--hv-dim); }

body.nav-albion.hud-v2 .an-tl .ws-tag > [data-part='gp'] { color: var(--hv-ink); }

/* THE WALLET CHIP (#3142): "Obols 1,240", between XP and Season, dressed as
   the XP chip is. Two different numbers on one row, each with its name. */
body.nav-albion.hud-v2 .an-tl .ws-obols {
  display: inline;
  flex: none;
  margin: 0;
  font-size: inherit;
  color: var(--hv-dim);
  text-shadow: none;
}

body.nav-albion.hud-v2 .an-tl .ws-obols[hidden] { display: none; }

body.nav-albion.hud-v2 .an-tl .ws-obols > i {
  font-style: normal;
  text-transform: none;
  font-size: inherit;
  color: var(--hv-dim);
}

body.nav-albion.hud-v2 .an-tl .ws-obols > b { font-weight: 400; color: var(--hv-ink); }

/* THE BUFF ROW (Wray, 2026-09-24: "Debuff overlapping the player frame").
   It is the plate's own last line, so it sits UNDER the frame and the name
   plate and can never cover them; it starts where the name plate's text
   does, clear of the ruby and the shield that hang below the frame. A gold
   rim is a buff, a red rim a debuff; the figure bottom right is seconds. */
body.nav-albion.hud-v2 .an-tl .ws-buffs {
  order: 8;
  flex: 0 0 100%;
  display: flex;
  flex-wrap: wrap;
  box-sizing: border-box;
  gap: calc(6 * var(--hv-k) * 1px);
  margin-top: calc(5 * var(--hv-k) * 1px);
  padding-left: calc(var(--pv-bust) + 22 * var(--hv-k) * 1px);
  min-width: 0;
}

body.nav-albion.hud-v2 .an-tl .ws-buffs[hidden] { display: none; }

body.nav-albion.hud-v2 .an-tl .ws-buff {
  position: relative;
  flex: none;
  box-sizing: border-box;
  width: calc((12 * var(--hv-k) + 10) * 1px);
  height: calc((12 * var(--hv-k) + 10) * 1px);
  background: var(--hv-well);
  box-shadow: 0 0 0 calc(var(--hv-k) * 1px) var(--hv-black), 0 0 0 calc(2 * var(--hv-k) * 1px) var(--hv-gold);
}

body.nav-albion.hud-v2 .an-tl .ws-buff.is-debuff {
  box-shadow: 0 0 0 calc(var(--hv-k) * 1px) var(--hv-black), 0 0 0 calc(2 * var(--hv-k) * 1px) var(--hv-foe);
}

/* a painted card face, cropped by the owner: not pixel art, so smoothed */
body.nav-albion.hud-v2 .an-tl .ws-buffic {
  position: absolute;
  inset: 0;
  background-repeat: no-repeat;
  image-rendering: auto;
}

body.nav-albion.hud-v2 .an-tl .ws-bufft {
  position: absolute;
  right: calc(-2 * var(--hv-k) * 1px);
  bottom: calc(-3 * var(--hv-k) * 1px);
  font-family: var(--hv-f-px);
  font-size: calc((2 * var(--hv-k) + 5) * 1px);
  font-weight: 400;
  line-height: 1;
  color: #fff;
  text-shadow: 0 calc(var(--hv-k) * 1px) 0 #000, calc(var(--hv-k) * 1px) 0 0 #000,
    calc(-1 * var(--hv-k) * 1px) 0 0 #000, 0 calc(-1 * var(--hv-k) * 1px) 0 #000;
  pointer-events: none;
}

body.nav-albion.hud-v2 .an-tl .ws-bufft:empty { display: none; }

/* the "+N" after the fifth icon: a phone's row keeps to one line (below) */
body.nav-albion.hud-v2 .an-tl .ws-buffmore { display: none; }

/* THE PHONE (390x844): k is 1, and the plate shares the line under the door
   row with the minimap. The chips row goes, as it does in the mock's phone;
   the house word is already hidden by round two's phone rule.

   ⭐THE PLATE RUNS TO 8px SHORT OF THE MINIMAP (#3069 S10, audit PH-13). It
   was a fixed 118 art pixels, 183px at 390, which cut a guest's handle and
   left a dead 51px before the map. The map's left edge is the frame's width
   less 12 and its 132px box, so the plate is that less 8 and its own 12 from
   the left: 226 at 390, 196 at 360. It never grows past the desktop plate
   (min), and the target keeps its own width (world-target-plate.css). */
@media (max-width: 560px) {
  body.nav-albion.hud-v2 .an-tl .ws-plate:not([data-role='target']) {
    width: min(calc(var(--pv-bust) + (14 + var(--pv-body) - 5) * var(--hv-k) * 1px), calc(var(--fw, 100vw) - 164px));
  }
  body.nav-albion.hud-v2 .an-tl .ws-plate:not([data-role='target']) .ws-platetext {
    width: calc(100% - var(--pv-bust) - 9 * var(--hv-k) * 1px);
  }
  body.nav-albion.hud-v2 .an-tl .ws-barrow { display: none; }
}

/* ⭐BUFFS ON A PHONE, IN A ROW THAT IS ALWAYS THERE (#3069 S10, audit PH-3,
   ruling 2, option A). With the row off, a phone held upright showed no
   Shell, no Focus, no Dash and no Hostile ground, and open-world combat is
   the MVP. It could not simply show: the target plate follows yours in the
   corner's flow, so a row that came and went would push it down mid-fight.
   So on a phone, and on any screen 540 tall or less (a phone held sideways:
   audit PH-5), the row's height is RESERVED whether or not anything is in
   it: one line, 24 tall, up to five 20px icons with their seconds, then
   "+N". Nothing below it ever moves, and nothing covers your frame.

   ⛔YOUR PLATE ONLY, never the target's (S10 review). The target never
   carries buffs, and a reserved band there pushed its Add friend and
   Profile 37px below its frame at 390x844, where they read as stray icons,
   and under the chat's tabs at 740x360. The target's row stays hidden. */
@media (max-width: 560px), (max-height: 540px) {
  body.nav-albion.hud-v2 .an-tl .ws-plate:not([data-role='target']) .ws-buffs,
  body.nav-albion.hud-v2 .an-tl .ws-plate:not([data-role='target']) .ws-buffs[hidden] {
    display: flex;
    flex-wrap: nowrap;
    align-items: flex-start;
    height: calc(24 * var(--hv-k) * 1px);
    gap: calc(4 * var(--hv-k) * 1px);
    margin-top: calc(4 * var(--hv-k) * 1px);
  }
  body.nav-albion.hud-v2 .an-tl .ws-plate:not([data-role='target']) .ws-buff {
    width: calc((12 * var(--hv-k) + 8) * 1px);
    height: calc((12 * var(--hv-k) + 8) * 1px);
  }
  body.nav-albion.hud-v2 .an-tl .ws-plate:not([data-role='target']) .ws-buff:nth-child(n+6) { display: none; }
  body.nav-albion.hud-v2 .an-tl .ws-plate:not([data-role='target']) .ws-buffmore {
    display: block;
    flex: none;
    align-self: center;
    font-family: var(--hv-f-px);
    font-size: calc((2 * var(--hv-k) + 5) * 1px);
    font-weight: 400;
    line-height: 1;
    color: var(--hv-ink);
    text-shadow: 0 calc(var(--hv-k) * 1px) 0 #000;
  }
}

/* ⭐THE WALLET STAYS ON THE PHONE (#3142). The rule above drops the chips
   row, as the mock's phone does, and with it went the only place the Obols
   show. A phone is where the smoke checks are ticked, and a fee is only
   checkable against a balance you can see, so the row comes back holding the
   wallet alone: the XP figure is on its bar and the season score is a
   ladder's business. One steady line, so the target plate under this one
   moves once, not whenever a buff comes or goes (the reason the buff row
   stays off). A hidden row stays hidden: `.ws-barrow[hidden]` above is the
   stronger rule. */
@media (max-width: 560px) {
  body.nav-albion.hud-v2 .an-tl .ws-barrow { display: flex; }
  body.nav-albion.hud-v2 .an-tl .ws-barrow > .ws-xpchip,
  body.nav-albion.hud-v2 .an-tl .ws-barrow > .ws-tag { display: none; }
}

}
/* end of @layer corners */
