/* ═══════════════════════════════════════════════════════════════════════
   world-chat-v2.css — THE CHAT PANEL v2 (GH #3069 S5, the HUD pass).

   The v7 mock's chat, which Wray ruled "build it" on 2026-09-24: the
   generated kit-B panel bottom-left, tabs Local / Guild / System on top of
   it, a history with timestamps and names in their colour, the input and a
   gold send button, and at rest the panel dimmed to its last four lines.
   Component: public/js/world-chat-panel.js (the frame); owner:
   public/js/world-presence.js (chat itself); markup:
   prototype/the-hall-3d/web/tpl-chat.html.

   Every rule starts at `body.hud-v2 #world-chat-panel` or reads a token
   only that class sets. The panel exists only when world-presence.js
   mounted it (FEATURE_WORLD_HUD_V2 or ?hud=1, and the template on the
   page), so with the flag off this file styles nothing and the old strip
   is untouched.

   ── THE LAYER ───────────────────────────────────────────────────────────
   `corners`, one block. Two reasons, both about the form presence moves
   into this panel:
     - #world-chat is styled by CHAT_CSS (`module`) as a fixed strip and by
       world-skin.css (`skin`) as the foot tray. This layer outranks both on
       every normal declaration whatever the specificity, so each property
       they set is ANSWERED here (the lesson world-skin.css records three
       times: override half of a placement and the other half stays).
     - the stack above the panel (the legacy plank and the guide's bubble;
       Nerm's strip stood here until #3069 S6 hid it under the HUD pass) is
       placed by corners and nerm rules; lifting it has to outrank them.
   What this layer cannot beat: the skin's `font-family: ... !important` on
   `#world-chat`, its input and its buttons (an important declaration in a
   LOWER layer wins). So the input keeps the skin's VT323, the send button's
   Press Start is hidden with its text, and the tabs, which sit outside the
   form, take their font from here.

   ── THE CHROME PIXEL ────────────────────────────────────────────────────
   Kit B at `--hv-k` (world-hud-v2.css): 2 at 1920x1080, where every piece
   lands on the mock's own pixels (panel rim 24, tab rims 10, the input's 8,
   the track 18 wide, the thumb 22x42). Two pieces are drawn at a whole
   scale of their OWN, because the chat sheet cut them at a finer pixel
   than its frame: the send button at k (52x48 at 1920; the mock squeezed
   it to 44x40, which is no whole scale of 26x24) and the unread badge at
   1 until k is 4 (22 at 1920, near the mock's 18). Type does not follow k
   (pixel fonts are crisp only at their own steps): Press Start 2P 8px and
   VT323 16 to 20px, with a step up at k 3 and 4.

   ── WHERE IT SITS, and what it keeps clear of ──────────────────────────
   Bottom-left, inside the picture (--fx, --fb), 12 chrome pixels in (24 at
   1920, the mock's). Its width stops short of the v2 action bar
   (world-actionbar.css): that bar is centred and pushed right of a 348px
   column, so its left end is max(frame/2 - half its rail, 348) from the
   frame's edge. The half widths are that file's (73 rail pixels at
   --ab-s 3, 4.5 and 6, three quarters of the mock's since 2026-09-29; 176
   for the one-row bar under 1280 wide or 540 tall). On a phone (under 708 wide, where that bar spans the screen) the
   panel stands on top of the bar instead, off the measured --w0bar-h
   world-wave0.js publishes, and clear of the CARDS door riding the bar's
   right end.
   ═══════════════════════════════════════════════════════════════════════ */
@layer base, module, skin, nerm, corners;

@layer corners {
/* ── the numbers, on <body> so the stack above can read them ─────────── */
body.hud-v2 {
  --chat-left: calc(var(--fx, 0px) + 12 * var(--hv-k, 1) * 1px);
  --chat-bottom: calc(var(--fb, var(--fy, 0px)) + 12 * var(--hv-k, 1) * 1px);
  /* a small window (k 1: 1280 to 1439, or under 810 tall) */
  --chat-w: 320px;
  --chat-h-open: 232px;
  --chat-h-rest: 150px;
  --chat-font: 16px;
  --chat-tab-font: 8px;
  --chat-gap: 2px;
  /* the unread badge's own whole scale (see the header) */
  --chat-bk: 1;
  /* the v2 action bar's half rail and the column it keeps clear */
  --chat-bar-half: 219px;
  --chat-bar-clear: 348px;
  /* how high the panel reaches: the stack above it stands on this (the
     foot of this file). Open by default; the rule below drops it to the
     rest height while the panel rests, so the stack sits on the panel
     rather than floating a row of empty world above it. */
  --chat-lift: calc(var(--chat-bottom) + var(--chat-h-open));
}
body.hud-v2:has(#world-chat-panel[data-state='rest']) {
  --chat-lift: calc(var(--chat-bottom) + var(--chat-h-rest));
}
@media (max-width: 1279px), (max-height: 540px) {
  body.hud-v2 { --chat-bar-half: 176px; }
}
@media (max-height: 540px) {
  body.hud-v2 { --chat-h-open: 180px; --chat-h-rest: 120px; }
}
/* the mock's own size, 1920x1080 */
@media (min-width: 1440px) and (min-height: 810px) {
  body.hud-v2 {
    --chat-w: 500px;
    --chat-h-open: 292px;
    --chat-h-rest: 206px;
    --chat-font: 20px;
    --chat-gap: 3px;
  }
}
@media (min-width: 2400px) and (min-height: 1350px) {
  body.hud-v2 {
    --chat-w: 750px;
    --chat-h-open: 438px;
    --chat-h-rest: 309px;
    --chat-font: 30px;
    --chat-tab-font: 16px;
    --chat-gap: 4px;
    --chat-bar-half: 328.5px;
  }
}
@media (min-width: 3360px) and (min-height: 1890px) {
  body.hud-v2 {
    --chat-w: 1000px;
    --chat-h-open: 584px;
    --chat-h-rest: 412px;
    --chat-font: 40px;
    --chat-tab-font: 16px;
    --chat-gap: 6px;
    --chat-bk: 2;
    --chat-bar-half: 438px;
  }
}
/* a phone: the bar spans the screen, so the panel stands on it. The mock's
   phone size is its at-rest box (262x122); open, it grows up to take the
   input. */
@media (max-width: 707px) {
  body.hud-v2 {
    --chat-left: 10px;
    --chat-bottom: calc(var(--w0bar-h, 110px) + 8px);
    --chat-w: min(262px, calc(100vw - 20px));
    --chat-h-open: 200px;
    --chat-h-rest: 122px;
    --chat-font: 16px;
    --chat-gap: 2px;
  }
}

/* ── the panel ──────────────────────────────────────────────────────── */
body.hud-v2 #world-chat-panel {
  position: fixed;
  left: var(--chat-left);
  bottom: var(--chat-bottom);
  width: min(var(--chat-w),
    calc(max(var(--fw, 100vw) / 2 - var(--chat-bar-half), var(--chat-bar-clear))
      - 12 * var(--hv-k, 1) * 1px - 12px));
  height: var(--chat-h-open);
  box-sizing: border-box;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-columns: minmax(0, 1fr);
  /* over the corners (38), under the action bar (42) and every sheet (60) */
  z-index: 41;
  margin: 0;
  /* the box itself is not a target: its top row is the tab strip, which
     runs the full width, and the stretch right of the last tab is world
     (see .wc2-tabs). The body and the tabs take their presses back, and a
     press on either still bubbles here to open the panel at rest. */
  pointer-events: none;
  font-family: var(--hv-f-vt);
}
body.hud-v2 #world-chat-panel[data-state='rest'] {
  height: var(--chat-h-rest);
  cursor: pointer;
}
@media (max-width: 707px) {
  body.hud-v2 #world-chat-panel { width: var(--chat-w); }
}
/* the whole-picture view hides every piece of chrome, as it hides the strip */
body.hud-v2.ws-full #world-chat-panel { display: none; }

/* ── the tabs: chat-tab.png, chat-tabon.png (5 5 1 5) ─────────────────── */
body.hud-v2 #world-chat-panel .wc2-tabs {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  gap: calc(1 * var(--hv-k, 1) * 1px);
  padding-left: calc(7 * var(--hv-k, 1) * 1px);
  /* the selected tab laps over the panel's top rim, as in the mock */
  margin-bottom: calc(-2 * var(--hv-k, 1) * 1px);
  min-width: 0;
  /* the row runs the panel's full width, and the strip right of the last
     tab is world, not chat: a press there walks the cat (and rests an open
     panel) instead of opening it. The tabs take their own presses back. */
  pointer-events: none;
}
/* ANSWERS world-skin.css's `.wp-chan` (tab-off.png, 22px tall, VT323 15px)
   and its left-rail variant: the same button, a different frame */
body.hud-v2 #world-chat-panel .wp-chan {
  position: relative;
  box-sizing: border-box;
  flex: 0 0 auto;
  height: auto;
  min-width: 0;
  margin: 0;
  border-style: solid;
  border-width: 0;
  border-radius: 0;
  border-image: url('/assets/ui/kitb/chat-tab.png?v=2026-09-24a') 5 5 1 5 fill /
    calc(5 * var(--hv-k, 1) * 1px) calc(5 * var(--hv-k, 1) * 1px)
    calc(1 * var(--hv-k, 1) * 1px) calc(5 * var(--hv-k, 1) * 1px) stretch;
  background: none;
  box-shadow: none;
  padding: calc(5 * var(--hv-k, 1) * 1px) calc(7 * var(--hv-k, 1) * 1px);
  font: 400 var(--chat-tab-font)/1 var(--hv-f-px);
  letter-spacing: .04em;
  text-transform: none;
  color: #aeb8c8;
  text-shadow: none;
  image-rendering: pixelated;
  cursor: pointer;
  opacity: 1;
  pointer-events: auto;
}
/* A THUMB'S TAB (#3069 S11, PH-8/C8). The tabs are drawn 20 tall on a phone
   and a thumb wants 44: on a touch screen each tab's target reaches UP to 44
   into the world above the panel, transparent, so the art is the same and
   nothing in the panel is covered (the row's own stretch right of the last
   tab stays world, as above). */
@media (pointer: coarse) {
  body.hud-v2 #world-chat-panel .wp-chan::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: max(100%, 44px);
  }
}
body.hud-v2 #world-chat-panel .wp-chan:hover { color: #d4dbe6; }
body.hud-v2 #world-chat-panel .wp-chan:focus-visible {
  outline: 2px solid var(--hv-gold-hi, #e3c79a);
  outline-offset: 1px;
}
body.hud-v2 #world-chat-panel .wp-chan.is-on {
  border-image-source: url('/assets/ui/kitb/chat-tabon.png?v=2026-09-24a');
  padding-top: calc(6 * var(--hv-k, 1) * 1px);
  padding-bottom: calc(6 * var(--hv-k, 1) * 1px);
  color: #3b2a18;
}
/* the unread badge: chat-badge.png whole, off the tab's top right */
body.hud-v2 #world-chat-panel .wc2-badge {
  position: absolute;
  right: calc(-3 * var(--hv-k, 1) * 1px);
  top: calc(-3 * var(--hv-k, 1) * 1px);
  width: calc(22px * var(--chat-bk, 1));
  height: calc(22px * var(--chat-bk, 1));
  display: grid;
  place-items: center;
  background: url('/assets/ui/kitb/chat-badge.png?v=2026-09-24a') 0 0 / 100% 100% no-repeat;
  image-rendering: pixelated;
  font: 400 calc(8px * var(--chat-bk, 1))/1 var(--hv-f-px);
  color: #fff;
  pointer-events: none;
}
body.hud-v2 #world-chat-panel .wc2-badge[hidden] { display: none; }
/* a tab with a count makes room for it: the badge reaches 22 badge pixels
   less its 3 chrome pixels of overhang into the tab, and at k 1 that is
   past the label's own 7 of padding (measured at 1280: it sat on the "d"
   of Guild). The tab grows while it has news and gives it back on reading. */
body.hud-v2 #world-chat-panel .wp-chan[data-unread] {
  padding-right: max(calc(7 * var(--hv-k, 1) * 1px),
    calc(22px * var(--chat-bk, 1) - 3 * var(--hv-k, 1) * 1px + 2px));
  /* ...and the badge's 3 chrome pixels of overhang past its own tab would
     land on the next one (the row's gap is 1): room for them, so the badge
     never sits on a neighbour (review of #3100; the mock only badged the
     last tab, so it never showed this) */
  margin-right: calc(3 * var(--hv-k, 1) * 1px);
}

/* ── the body: chat-panel.png (12) ─────────────────────────────────────── */
body.hud-v2 #world-chat-panel .wc2-body {
  position: relative;
  box-sizing: border-box;
  min-height: 0;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto auto;
  grid-template-columns: minmax(0, 1fr);
  border-style: solid;
  border-width: 0;
  border-image: url('/assets/ui/kitb/chat-panel.png?v=2026-09-24a') 12 fill /
    calc(12 * var(--hv-k, 1) * 1px) stretch;
  padding: calc(8 * var(--hv-k, 1) * 1px) calc(17 * var(--hv-k, 1) * 1px)
    calc(7 * var(--hv-k, 1) * 1px) calc(9 * var(--hv-k, 1) * 1px);
  image-rendering: pixelated;
  pointer-events: auto;
}

/* ── the log ──────────────────────────────────────────────────────────── */
body.hud-v2 #world-chat-panel .wc2-log {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--chat-gap);
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* the drawn bar replaces the browser's (world-chat-panel.js works it) */
  scrollbar-width: none;
  font: 400 var(--chat-font)/1.1 var(--hv-f-vt);
  color: #e9dcc0;
  cursor: auto;
}
body.hud-v2 #world-chat-panel .wc2-log::-webkit-scrollbar { display: none; }
/* open, a scrolled history is cut by the log's top edge right under the
   rim, and a row of half glyphs showed there (review of #3100). A fade one
   line tall takes it, as the mock's rest log fades its top: clear for its
   first 40%, where a sliver of a cut line would sit, then up to full over
   the rest (a plain 10px fade still left the lower half of a cut line
   legible, measured at 1920). The same height of padding keeps the FIRST
   line clear of the fade when the history is scrolled right to the top. */
body.hud-v2 #world-chat-panel[data-state='open'] .wc2-log {
  padding-top: calc(var(--chat-font) * 1.1);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0,
    transparent calc(var(--chat-font) * .45), #000 calc(var(--chat-font) * 1.1));
  mask-image: linear-gradient(to bottom, transparent 0,
    transparent calc(var(--chat-font) * .45), #000 calc(var(--chat-font) * 1.1));
}
/* ANSWERS world-skin.css's `.wp-line` family (margin, gold names, the
   dimmed replay, the italic emote, the loud legendary) */
body.hud-v2 #world-chat-panel .wp-line {
  flex: 0 0 auto;
  margin: 0;
  color: #e9dcc0;
  font-style: normal;
  letter-spacing: 0;
  text-transform: none;
  opacity: 1;
  white-space: normal;
  word-break: normal;
  overflow-wrap: anywhere;
}
/* lines stand on the bottom while there are few, and scroll when there are
   many (justify-content: flex-end would strand the overflow at the top,
   where a scroll cannot reach it) */
body.hud-v2 #world-chat-panel .wp-line:first-child { margin-top: auto; }
body.hud-v2 #world-chat-panel .wc2-t {
  /* the HUD's quiet ink, not a grey of its own (#3069 S11, C14: #6f7d8f
     measured 3.29:1 on the panel; the token is raised where it is set) */
  color: var(--hv-mute, #8a98aa);
  margin-right: calc(3 * var(--hv-k, 1) * 1px);
  font-style: normal;
}
body.hud-v2 #world-chat-panel .wp-line b.wc2-n {
  font-weight: 400;
  color: var(--c, #e7c77f);
  /* a house colour is picked for a crest, not for type on slate: mixed
     toward white it keeps its hue and reads (Nighthollow's #7B2D8E is
     near invisible on the panel otherwise) */
  color: color-mix(in srgb, var(--c, #e7c77f) 68%, #fff);
}
body.hud-v2 #world-chat-panel .wp-line.is-sys { color: var(--hv-sys, #93b5d8); }
body.hud-v2 #world-chat-panel .wp-line.is-nerm { color: #bfe0ff; }
body.hud-v2 #world-chat-panel .wp-line.is-nerm b.wc2-n { color: #7fb8ff; }
body.hud-v2 #world-chat-panel .wp-line.is-emote { color: #b9a37f; font-style: italic; }
body.hud-v2 #world-chat-panel .wp-line.is-old { opacity: .7; }
body.hud-v2 #world-chat-panel .wp-line.is-loud {
  text-transform: uppercase;
  font-style: normal;
  letter-spacing: .04em;
  color: var(--hv-gold-hi, #e3c79a);
}

/* ── the scrollbar: chat-track.png (caps of 8) and chat-thumb.png whole ── */
body.hud-v2 #world-chat-panel .wc2-track {
  position: absolute;
  right: calc(6 * var(--hv-k, 1) * 1px);
  top: calc(8 * var(--hv-k, 1) * 1px);
  /* down to the input row: the body's foot rim, the row, its margin */
  bottom: calc(36 * var(--hv-k, 1) * 1px);
  width: calc(9 * var(--hv-k, 1) * 1px);
  box-sizing: border-box;
  border-style: solid;
  border-width: 0;
  border-image: url('/assets/ui/kitb/chat-track.png?v=2026-09-24a') 8 0 8 0 fill /
    calc(8 * var(--hv-k, 1) * 1px) 0 calc(8 * var(--hv-k, 1) * 1px) 0 stretch;
  image-rendering: pixelated;
  cursor: pointer;
  touch-action: none;
}
/* the thumb travels INSIDE the track's end caps, 4 art pixels clear of
   each end, as the mock draws it (`bottom: 8px` at 2): from 4k down to the
   track less the thumb's 21 and the two insets. world-chat-panel.js maps a
   drag with the same two figures (THUMB_INSET, THUMB_ART_H). */
body.hud-v2 #world-chat-panel .wc2-thumb {
  position: absolute;
  left: calc(-1 * var(--hv-k, 1) * 1px);
  width: calc(11 * var(--hv-k, 1) * 1px);
  height: calc(21 * var(--hv-k, 1) * 1px);
  top: calc(4 * var(--hv-k, 1) * 1px
    + (100% - 29 * var(--hv-k, 1) * 1px) * var(--wc2-at, 1));
  background: url('/assets/ui/kitb/chat-thumb.png?v=2026-09-24a') 0 0 / 100% 100% no-repeat;
  image-rendering: pixelated;
  cursor: grab;
  touch-action: none;
}
/* on a whole pixel where the browser can round (a var() in a declaration
   the browser rejects goes invalid at computed-value time, so the snap is
   behind @supports, as world-hud-v2.css does for the bar fill) */
@supports (top: round(down, 5px, 2px)) {
  body.hud-v2 #world-chat-panel .wc2-thumb {
    top: round(down, calc(4 * var(--hv-k, 1) * 1px
      + (100% - 29 * var(--hv-k, 1) * 1px) * var(--wc2-at, 1)), 1px);
  }
}
body.hud-v2 #world-chat-panel .wc2-track.is-idle .wc2-thumb { cursor: default; }

/* ── the input row: THE FORM presence moved in ─────────────────────────
   Every property CHAT_CSS and the skin's tray set on #world-chat is
   answered: position fixed, left/top/bottom, the translate, the width
   sums, the 44px and tray heights, the tray's ground, its gold top border,
   its padding and gap, its z-index, and `#world-chat > * { height: 100% }`. */
body.hud-v2 #world-chat-panel .wc2-formslot {
  min-width: 0;
  margin-top: calc(5 * var(--hv-k, 1) * 1px);
  /* the row runs on under the scrollbar's column to the frame's inner edge */
  margin-right: calc(-9 * var(--hv-k, 1) * 1px);
}
body.hud-v2 #world-chat-panel #world-chat {
  position: static;
  left: auto;
  right: auto;
  top: auto;
  bottom: auto;
  transform: none;
  width: auto;
  min-width: 0;
  max-width: none;
  height: auto;
  flex: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  z-index: auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) calc(26 * var(--hv-k, 1) * 1px);
  align-items: center;
  justify-content: stretch;
  gap: calc(4 * var(--hv-k, 1) * 1px);
}
body.hud-v2 #world-chat-panel #world-chat > * { height: auto; }
/* no verbs and no Chat plank in the panel: the verbs are the slash
   prefixes (/w /t /s), as they already are in prod, where the left-rail
   mount hides them; the panel itself is what the plank opened */
body.hud-v2 #world-chat-panel #world-chat .wp-verb,
body.hud-v2 #world-chat-panel #world-chat .wp-tab { display: none; }
body.hud-v2 #world-chat-panel #world-chat input {
  display: block;
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  max-width: none;
  height: calc(24 * var(--hv-k, 1) * 1px);
  flex: none;
  margin: 0;
  padding: 0 calc(6 * var(--hv-k, 1) * 1px);
  border-style: solid;
  border-width: 0;
  border-radius: 0;
  border-image: url('/assets/ui/kitb/chat-input.png?v=2026-09-24a') 4 fill /
    calc(4 * var(--hv-k, 1) * 1px) stretch;
  background: none;
  box-shadow: none;
  outline: none;
  image-rendering: pixelated;
  font-size: var(--chat-font);
  line-height: 1;
  color: #e9dcc0;
}
body.hud-v2 #world-chat-panel #world-chat input::placeholder { color: #6c7888; }
body.hud-v2 #world-chat-panel #world-chat input:focus {
  box-shadow: none;
  outline: 2px solid rgba(227, 199, 154, .55);
  outline-offset: -2px;
}
/* a guest's: disabled by design, with the line that says how to speak in
   it (COPY.muted). Readable, not a broken box. */
body.hud-v2 #world-chat-panel #world-chat.wp-muted input {
  opacity: .72;
  cursor: not-allowed;
}
/* send: chat-send.png whole, at k. The word stays as its accessible name
   and is hidden from sight (its font is the skin's, !important). */
body.hud-v2 #world-chat-panel #world-chat button[type='submit'] {
  display: block;
  box-sizing: border-box;
  width: calc(26 * var(--hv-k, 1) * 1px);
  height: calc(24 * var(--hv-k, 1) * 1px);
  flex: none;
  margin: 0;
  padding: 0;
  border-style: none;
  border-width: 0;
  border-image: none;
  border-radius: 0;
  background: url('/assets/ui/kitb/chat-send.png?v=2026-09-24a') 0 0 / 100% 100% no-repeat;
  box-shadow: none;
  image-rendering: pixelated;
  font-size: 0;
  color: transparent;
  text-shadow: none;
  overflow: hidden;
  opacity: 1;
  filter: none;
  transform: none;
  cursor: pointer;
}
body.hud-v2 #world-chat-panel #world-chat button[type='submit']:hover { filter: brightness(1.08); }
body.hud-v2 #world-chat-panel #world-chat button[type='submit']:active {
  transform: translateY(calc(1 * var(--hv-k, 1) * 1px));
  filter: brightness(.95);
}
body.hud-v2 #world-chat-panel #world-chat button[type='submit']:focus-visible {
  outline: 2px solid var(--hv-gold-hi, #e3c79a);
  outline-offset: 1px;
}
/* ⭐A THUMB'S ROW (#3069 S15, PH-F9). The input and Say are drawn 24 tall
   and a thumb wants 44. The art stays; on a touch screen the ROW ITSELF is
   44 tall, so its reach is its own box and nothing it grows into belongs to
   anyone else.
   ⛔NOT an overhanging band (S15 review). The first cut hung a transparent
   44px band 10px above and below a 24px row, and a 44px box round Say's
   centre. Measured with elementFromPoint at 390x844 and 768x1024: the band
   took the foot of the last chat line and 1 to 5px of the world under the
   panel, and Say's box took the right 5px of the input and the foot of the
   log's scrollbar, so a signed-in player tapping the end of the input SENT
   the line. Here the form's grid row is 44 (the body's grid gives the log
   20px less, all inside the panel), a press on its air goes to the input
   (world-presence.js), and Say's own box is 44 wide: its art drawn at its
   right edge, the extra reaching left across what used to be empty gap
   while the input gives up the same width. */
@media (pointer: coarse) {
  body.hud-v2 #world-chat-panel #world-chat {
    grid-template-columns: minmax(0, 1fr) max(44px, calc(26 * var(--hv-k, 1) * 1px));
    min-height: 44px;
  }
  body.hud-v2 #world-chat-panel #world-chat button[type='submit'] {
    width: max(44px, calc(26 * var(--hv-k, 1) * 1px));
    height: max(44px, calc(24 * var(--hv-k, 1) * 1px));
    background-position: right center;
    background-size: calc(26 * var(--hv-k, 1) * 1px) calc(24 * var(--hv-k, 1) * 1px);
  }
  /* the scrollbar stops above the taller row, as it stops above the drawn
     one (the body's foot rim 7, the row, its margin 5): it stood 15px into
     Say's box at 390x844 once the row was 44 */
  body.hud-v2 #world-chat-panel .wc2-track {
    bottom: calc(12 * var(--hv-k, 1) * 1px + max(44px, calc(24 * var(--hv-k, 1) * 1px)));
  }
}
body.hud-v2 #world-chat-panel #world-chat.wp-muted button[type='submit'] {
  opacity: .45;
  filter: grayscale(.4);
  cursor: not-allowed;
}

/* ── the line under the panel at rest ───────────────────────────────── */
body.hud-v2 #world-chat-panel .wc2-hint {
  margin: calc(3 * var(--hv-k, 1) * 1px) 0 0;
  min-width: 0;
  /* the tabs' size: it steps up with them from 2400 wide, where a fixed
     8px was a speck under a 750px panel (review of #3100) */
  font: 400 var(--chat-tab-font)/1 var(--hv-f-px);
  letter-spacing: .04em;
  /* the HUD's quiet ink (C14: #7d8a9b measured 3.93:1) */
  color: var(--hv-mute, #8a98aa);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* A GUEST'S LINE DOES NOT FIT A PHONE. "connect X or a wallet to speak" was
   about 250px of Press Start in a 236px box, and it read "...to spe..." (the
   line is "connect a wallet in Settings" since #3069 S15). The
   mock draws no hint on the phone at all, and a tap opens the panel onto
   the disabled input, whose placeholder says the same thing in full. A
   player's "Tap to talk" fits and stays. */
@media (max-width: 707px) {
  body.hud-v2 #world-chat-panel:has(#world-chat.wp-muted) .wc2-hint { display: none; }
}

/* ── A GUEST'S WAY IN: the line is a control (#3069, Wray 2026-09-26) ───
   "connect a wallet in Settings" was words pointing at a door the guest had
   to find. Now it is a button under the log, open or at rest, on a laptop
   and a phone, and since 2026-10-14 it registers (Wray: "Register an account
   to talk"): it sends the player to X to link X to this very account
   (world-presence.js register, register-x.js). Its words are longer than
   the old "Connect wallet to talk", so on a narrow phone it WRAPS to a
   second line between words instead of cutting them. Drawn on btngold.png, the one
   CTA a surface has (framed-v2.css `.btn--cta`), at the chrome's k, and
   lettered in small capitals: uppercase at the tab row's size with the
   letter-spacing of Settings' CONNECT WALLET (1.5px at 10px, .15em). While
   it shows, the words it replaces go. */
body.hud-v2 #world-chat-panel .wc2-cta {
  justify-self: start;
  align-self: end;
  box-sizing: border-box;
  max-width: 100%;
  min-width: 0;
  margin: calc(3 * var(--hv-k, 1) * 1px) 0 0;
  border-style: solid;
  border-width: calc(3 * var(--hv-k, 1) * 1px) calc(3 * var(--hv-k, 1) * 1px)
    calc(5 * var(--hv-k, 1) * 1px) calc(3 * var(--hv-k, 1) * 1px);
  border-image: url('/assets/ui/kitb/btngold.png?v=2026-09-24a') 3 3 5 3 fill /
    calc(3 * var(--hv-k, 1) * 1px) calc(3 * var(--hv-k, 1) * 1px)
    calc(5 * var(--hv-k, 1) * 1px) calc(3 * var(--hv-k, 1) * 1px) stretch;
  border-radius: 0;
  background: none;
  box-shadow: none;
  padding: calc(2 * var(--hv-k, 1) * 1px) calc(5 * var(--hv-k, 1) * 1px) calc(1 * var(--hv-k, 1) * 1px);
  font: 400 var(--chat-tab-font)/1.2 var(--hv-f-px);
  text-transform: uppercase;
  letter-spacing: .15em;
  color: #2a1c0c;
  text-shadow: none;
  white-space: normal;
  text-align: left;
  overflow: hidden;
  image-rendering: pixelated;
  cursor: pointer;
  pointer-events: auto;
}
body.hud-v2 #world-chat-panel .wc2-cta[hidden] { display: none; }
body.hud-v2 #world-chat-panel .wc2-cta:hover { filter: brightness(1.06); }
body.hud-v2 #world-chat-panel .wc2-cta:active {
  transform: translateY(calc(1 * var(--hv-k, 1) * 1px));
  filter: brightness(.95);
}
body.hud-v2 #world-chat-panel .wc2-cta:focus-visible {
  outline: 2px solid var(--hv-gold-hi, #e3c79a);
  outline-offset: 1px;
}
/* a thumb's target: 44 tall on a touch screen, the art stretched to it */
@media (pointer: coarse) {
  body.hud-v2 #world-chat-panel .wc2-cta { min-height: 44px; }
}
/* the words it replaces: the control says them, and does them */
body.hud-v2 #world-chat-panel .wc2-body:has(.wc2-cta:not([hidden])) .wc2-hint { display: none; }

/* ── OPEN and AT REST ────────────────────────────────────────────────────
   Open: the input row and the scrollbar, no hint. At rest (v7's
   `.chat2.rest`): the panel at .82, the tabs not selected at .75, the last
   four lines on one line each, no timestamps, no scrollbar, the hint in
   the input's place. The form is display:none at rest, never transparent:
   world-skin.js focuses the input at boot, and a hidden input holding
   focus would swallow every hotkey (world-keys.js ignores keys while
   typing). */
body.hud-v2 #world-chat-panel[data-state='open'] .wc2-hint { display: none; }
body.hud-v2 #world-chat-panel[data-state='rest'] .wc2-body { opacity: .82; }
body.hud-v2 #world-chat-panel[data-state='rest'] .wp-chan:not(.is-on) { opacity: .75; }
body.hud-v2 #world-chat-panel[data-state='rest'] .wc2-formslot,
body.hud-v2 #world-chat-panel[data-state='rest'] #world-chat,
body.hud-v2 #world-chat-panel[data-state='rest'] .wc2-track,
body.hud-v2 #world-chat-panel[data-state='rest'] .wc2-t { display: none; }
body.hud-v2 #world-chat-panel[data-state='rest'] .wc2-log {
  overflow: hidden;
  justify-content: flex-end;
  cursor: pointer;
}
body.hud-v2 #world-chat-panel[data-state='rest'] .wp-line:not(:nth-last-child(-n+4)) { display: none; }
body.hud-v2 #world-chat-panel[data-state='rest'] .wp-line {
  margin-top: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* ⭐THE NEWEST LINE, AND NERM'S, GET TWO ROWS (#3069 S11, HD-06). One row
   cut Nerm's arrival line to "...at the camp on the path. ..." and a beat to
   "its house is what it is good a...": the point of the line was the part
   cut. So at rest the newest line, and any Nerm or System line among the
   four shown, wraps to two rows and is cut after the second. Scoped to the
   four shown (:nth-last-child), so the rule above still hides the rest: a
   `display` here would otherwise out-weigh it and bring them back. */
body.hud-v2 #world-chat-panel[data-state='rest'] .wp-line:last-child,
body.hud-v2 #world-chat-panel[data-state='rest'] .wp-line.is-nerm:nth-last-child(-n+4),
body.hud-v2 #world-chat-panel[data-state='rest'] .wp-line.is-sys:nth-last-child(-n+4) {
  white-space: normal;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}
/* ⭐...AND ONLY WHOLE LINES SHOW (review of PR #3177). When those two-row
   lines together ran past the rest height, the log (standing on its
   bottom) sliced its top line through the letters under the rim.
   world-chat-panel.js fitRest measures and marks an older line that
   starts above the log's top; at rest it goes. After the rule above, and
   the class doubled, so its `display` wins over the two-row one. */
body.hud-v2 #world-chat-panel[data-state='rest'] .wp-line.wc2-cut.wc2-cut { display: none; }
/* ⭐THE REST STATE SITS ON ITS FULL RIM (#3069 S11, HD-05, PH-6, C13).
   chat-panel.png's rim is 12 chrome pixels and the body's foot padding was
   7, so the resting hint ("Enter to talk", a guest's "connect a wallet in
   Settings") was drawn on the bottom rail and against the corner stud, at
   every k. At rest the foot is the whole rim; open, the input row keeps its
   7, which the input's own frame clears. */
body.hud-v2 #world-chat-panel[data-state='rest'] .wc2-body {
  padding-bottom: calc(12 * var(--hv-k, 1) * 1px);
}
/* ⭐AND IT IS AS TALL AS WHAT IT SHOWS (HD-06): two lines no longer sit in a
   box built for four (a guest's panel at 1920 was 60% empty frame). It grows
   to --chat-h-rest and no further; the grid clamps its one flexible row to
   that height, so a long log still stands on the bottom and is cut at the
   top, as before. --chat-lift keeps the full rest height, so the stack
   above never moves as lines arrive. */
body.hud-v2 #world-chat-panel[data-state='rest'] {
  height: auto;
  max-height: var(--chat-h-rest);
}

/* ── THE STACK ABOVE THE PANEL ───────────────────────────────────────────
   Two things still live in this corner: the legacy PLAY ARENA plank
   (world-legacy-door.css, above the bar) and the guide's home bubble
   (nerm-guide.css: the island's chapters and Help's walkthrough). The panel
   takes the corner's foot, so each stands on top of it instead: the plank
   first, the bubble above the plank. They stand on the panel's top edge
   (--chat-lift), so opening chat lifts them with it, like a stack, and
   resting sets them back down. Only while the panel exists: with the old
   strip none of this applies.
   ⭐NERM'S AMBIENT STRIP (.wt-nerm) LEFT THIS STACK IN #3069 S6: under the
   HUD pass his lines are chat lines on the System tab (the tracker's and
   the beats'), and world-tracker.css hides the strip, so nothing here
   places it and nothing here folds the panel for it. */
body.hud-v2:has(#world-chat-panel) .wld-door {
  left: var(--chat-left);
  bottom: calc(var(--chat-lift) + 8px);
}
body.hud-v2:has(#world-chat-panel) #ng.ng-home .ng-bubble {
  bottom: calc(var(--chat-lift) + 8px);
}
/* on the plank, off its MEASURED height. It is drawn at the chrome's scale
   (50px at 1920, 59 at 2560, 68 at 3840), so a fixed allowance for it
   overlapped the plank from 2560 up (review of #3100). world-legacy-door.js
   publishes --wld-door-h; the fallback is its height at 1920. */
body.hud-v2:has(#world-chat-panel):has(.wld-door) #ng.ng-home .ng-bubble {
  bottom: calc(var(--chat-lift) + 8px + var(--wld-door-h, 50px) + 8px);
}
/* one left edge for the whole stack, the panel's (the bubble kept a 12px
   left while the panel and plank moved to 24, 36 and 48). Not beside an
   open left window: there it steps right of it, which is the window's rule
   (nerm-guide.css) and stays its. */
body.hud-v2:not(.ws-left-open):has(#world-chat-panel) #ng.ng-home .ng-bubble {
  left: var(--chat-left);
}

/* ── A SMALL SCREEN HAS ROOM FOR ONE THING IN THIS CORNER ────────────────
   (review of #3100, measured on the served page.) On a 390x844 phone the
   stack on top of an OPEN panel put the guide's bubble over your own cat
   (y 324 to 462), and on an 844x390 phone held sideways over your portrait
   and name; at rest, with its whole line showing, the bubble still reached
   y 403, the cat's lower half. So under 708 wide or 540 tall:
     - OPEN, the panel is the only thing here. The plank and the guide's
       bubble step out of sight (visibility, not layout: their own files
       still place them) and come back when chat rests.
     - AT REST while the guide is talking (its home bubble up: the island,
       or Help's walkthrough), the panel folds to its tab row, so the
       bubble stands low enough to clear the cat and the portrait. The tabs
       keep their badges, and a press on them opens chat as before.
   (Nerm's strip and his beat panel folded it too until #3069 S6, which
   moved his lines into chat and hid the strip under the HUD pass.) */
@media (max-width: 707px), (max-height: 540px) {
  body.hud-v2 {
    /* the tab row: the selected tab's type and its 6 + 6 of padding */
    --chat-h-fold: calc(var(--chat-tab-font) + 12 * var(--hv-k, 1) * 1px);
  }
  body.hud-v2:has(#world-chat-panel[data-state='open']) .wld-door,
  body.hud-v2:has(#world-chat-panel[data-state='open']) #ng.ng-home .ng-bubble {
    visibility: hidden;
  }
  body.hud-v2:has(#ng.ng-home:not([hidden])) #world-chat-panel[data-state='rest'] {
    height: var(--chat-h-fold);
  }
  body.hud-v2:has(#ng.ng-home:not([hidden])) #world-chat-panel[data-state='rest'] .wc2-body {
    display: none;
  }
  body.hud-v2:has(#ng.ng-home:not([hidden])):has(#world-chat-panel[data-state='rest']) {
    --chat-lift: calc(var(--chat-bottom) + var(--chat-h-fold));
  }
}
/* A SHORT PHONE (under 760 tall: 390x664 is the browser viewport the guide
   is written for, nerm-guide.css) has room for even less. Measured there:
   the guide's bubble on the folded tabs still sat 24px higher than main
   puts it, and main's only just clears the cat. So:
     - (Nerm's one-line strip, which folded the resting panel here too, is
       hidden under the HUD pass since #3069 S6.)
     - the guide talking: the panel steps aside until it is done, and the
       plank and the bubble stand exactly where main has them (the plank 12
       over the bar, the bubble 68: --chat-bottom less 4 is the bar plus 4,
       and the stack's own 8 + plank + 8 on top of it make those two).
     - open, the panel is 180 tall, not 200, so its top clears the cat. */
@media (max-width: 707px) and (max-height: 759px) {
  body.hud-v2 { --chat-h-open: 180px; }
  body.hud-v2:has(#ng.ng-home:not([hidden])) #world-chat-panel[data-state='rest'] {
    display: none;
  }
  body.hud-v2:has(#ng.ng-home:not([hidden])):has(#world-chat-panel[data-state='rest']) {
    --chat-lift: calc(var(--chat-bottom) - 4px);
  }
}

/* ── NEVER A SLIVER UNDER A WINDOW (#3069 S11: HD-09, WIN-4, WB-07, C4) ────
   The panel is z 41 and every window 60, so a window over it hid most of it
   and left the rest showing: beside a left dock (Leaderboard, Rooms, Play,
   Guild: 433px of window over a 500px panel at 1920) a strip of frame and a
   cut line ("path. ...") stood out to the right, and under the Map window
   and the centred windows the guest line showed below their foot. It read
   as a rendering fault. So while one of those is open the panel steps out
   of sight, and comes back as it was when the window shuts. `visibility`,
   not display: it keeps its place and its state, and presence keeps
   drawing into it.
     - a LEFT dock: world-shell.js puts `ws-left-open` on <body>
     - a CENTRED window, the Map window included (world-map-v2.js opens it
       docked 'map', side 'centre'); named twice so a Map window that ever
       docks elsewhere still hides it
   A RIGHT dock does not reach the bottom-left, so on a desktop the panel
   stays beside it. */
body.hud-v2.ws-left-open #world-chat-panel,
body.hud-v2:has(.ws-sheet[data-side='centre']:not([hidden])) #world-chat-panel,
body.hud-v2:has(.ws-sheet[data-door='map']:not([hidden])) #world-chat-panel {
  visibility: hidden;
}
/* ...and on a phone (the corner's breakpoint, 560, or a short screen held
   sideways) a window covers the picture, docked or not, so under ANY open
   window the panel goes. (The other HUD pieces a phone hides under a window
   are another slice's, #3069 S12.) */
@media (max-width: 560px), (max-height: 540px) {
  body.hud-v2:has(.ws-sheet:not([hidden])) #world-chat-panel { visibility: hidden; }
}
}
/* end of @layer corners */
