/* ── OCTOPONG · room / lobby ─────────────────────────────────
   Built from References/02_Room or Lobby: the code plate and match
   settings down the left, the roster ringed around the arena in the
   middle, mode + rule summary + players + START MATCH down the
   right, and an honest status strip along the bottom.

   Structure comes from theme.css (.panel, .panel-head, .btn, .pill,
   .chip, .scr-title, .statusbar). Everything below is either new or
   scoped inside .lobby.

   The same two traps as results.css and pause.css, for the same
   reasons — both cost a full review round in this codebase:

     1. NEVER outline a clipped shape with a `z-index:-1` ::before.
        clip-path and filter each open a stacking context, and a
        negative-z child of one paints ABOVE its parent background,
        flooding the face. Use the chained zero-blur drop-shadows.

     2. A clipped element clips its own `outline`, so `outline` gives
        these shapes NO focus ring at all. Focus is drawn by
        brightening `--edge` in that same chain, plus a guaranteed
        `inset` box-shadow that clip-path cannot eat.
   ─────────────────────────────────────────────────────────── */

.lobby{
  --lb-label:#a9c7dd;         /* 7.0:1 on the lightest panel stop */
  --lb-note:#bcd6e8;          /* 8.6:1 — body copy, never --ink-faint */
  --lb-rose:#ff8fbc;          /* 5.8:1 — the "not ready" red */
  --lb-line:rgba(140,190,230,.20);
  --lb-row:#101f42;
  --lb-plate:#0a1024;
  font-size:calc(16px * var(--op-ui-scale, 1));
  grid-template-rows:auto minmax(0,1fr) auto;
}

/* the arena keeps playing behind the shell, but a lobby is a room,
   not a match — dim it hard enough that 12px body copy holds up */
.lobby::before{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:
    radial-gradient(ellipse 78% 74% at 50% 46%, rgba(11,24,56,.55), rgba(4,7,18,.93) 72%),
    linear-gradient(180deg, rgba(4,7,18,.94), rgba(4,7,18,.80) 26%,
                    rgba(4,7,18,.80) 74%, rgba(4,7,18,.96));
}

/* theme.css's .panel-head is white on #ff3d8b, which measures 3.34:1
   and fails AA. Same shape, darker ramp, 5.4:1. Scoped so no other
   screen shifts under me. */
.lobby .panel-head{
  display:flex; align-items:center; gap:10px;
  background:linear-gradient(180deg,#c8206a,#8f0f4a);
  font-size:13px; letter-spacing:.13em; padding:9px 16px;
}
.lobby .panel-head .hd-r{
  margin-left:auto; font:800 11px/1 var(--ui); letter-spacing:.12em;
  color:#fff;                                  /* 5.4:1 on the head */
}
/* theme.css's .aqua / .gold heads are a background AND a dark text
   colour. Overriding .panel-head above wins the background back to
   magenta but leaves the dark text on it at 3.1:1, so both variants
   have to be restated whole. Measured: 4.9:1 and 5.7:1 at the darker
   stop of each gradient. */
.lobby .panel-head.aqua{
  background:linear-gradient(180deg,var(--aqua),var(--aqua-lo)); color:#05221f; }
.lobby .panel-head.gold{
  background:linear-gradient(180deg,var(--gold),var(--gold-lo)); color:#2a1600; }
.lobby .panel-head.aqua .hd-r{ color:#05221f; }
.lobby .panel-head.gold .hd-r{ color:#2a1600; }
.lobby .panel{ padding:14px 16px; }
/* theme.css bleeds .panel-head to the panel's own 16/18 padding with
   a negative margin. This screen runs a tighter panel, so the head
   has to be re-bled to match — 2px of overhang each side is enough to
   put a horizontal scrollbar under every column. */
.lobby .panel-head{ margin:-14px -16px 12px; }

.sr-only{
  position:absolute !important; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap;
}

/* ── header ──────────────────────────────────────────────── */
.lobby .lb-head{
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  padding:12px 20px 4px; zoom:var(--op-ui-scale,1);
}
/* .scr-title is authored centred with a bottom margin for the mode
   screen; here it is a header item sitting beside the back button */
.lobby .lb-head .scr-title{
  margin:0; text-align:left; font-size:clamp(24px,2.7vw,38px);
  -webkit-text-stroke:5px var(--outline);
}
.lobby .chip{ font-size:11px; letter-spacing:.1em; }
.lobby .chip.warn{
  background:linear-gradient(180deg,rgba(94,62,10,.96),rgba(56,34,4,.96));
  color:#ffdf9a; box-shadow:0 0 0 2px var(--outline),0 3px 0 rgba(0,0,0,.5);
}
.lobby .chip.warn b{ color:var(--gold-hi); }
.lobby .chip .ci{ display:block; width:14px; height:14px; flex:none; color:var(--gold); }
.lobby .chip .ci svg{ width:100%; height:100%; display:block; }

/* ── body grids ──────────────────────────────────────────── */
.lobby .lb-body{
  display:grid; gap:16px; padding:8px 20px 8px; min-height:0; align-items:start;
}
/* centred rather than top-aligned: the three stacks are different
   heights and start-aligning them leaves a third of the frame empty
   under the shortest one */
.lobby .lb-body.browse{
  grid-template-columns:minmax(280px,25vw) minmax(0,1fr) minmax(260px,23vw);
  align-items:center;
}
.lobby .lb-body.room{   grid-template-columns:minmax(268px,23vw) minmax(0,1fr) minmax(300px,26vw); }

.lobby .lb-col{
  display:flex; flex-direction:column; gap:14px; min-width:0;
  zoom:var(--op-ui-scale,1);
  max-height:calc(100% / var(--op-ui-scale,1));
  overflow:auto; padding-bottom:4px;
  scrollbar-width:thin; scrollbar-color:#2c4a86 transparent;
}
.lobby .lb-col::-webkit-scrollbar{ width:9px; }
.lobby .lb-col::-webkit-scrollbar-thumb{ background:#2c4a86; border-radius:99px; }
/* the ring is not a scroller — it sizes to the column and centres */
.lobby .lb-body.room{ align-items:stretch; }
.lobby .lb-col.mid{ overflow:visible; justify-content:center; gap:18px; }

/* ── shared small parts ──────────────────────────────────── */
.lobby .lb-lab{
  display:flex; align-items:center; gap:7px; margin:10px 0 5px;
  font:800 10.5px/1.3 var(--ui); letter-spacing:.16em; text-transform:uppercase;
  color:var(--lb-label);
}
.lobby .lb-lab:first-child{ margin-top:2px; }
.lobby .lb-lab b{ color:var(--gold); letter-spacing:.1em; }
.lobby .lb-note{
  margin:8px 0 10px; font:600 12px/1.55 var(--ui); color:var(--lb-note);
}
.lobby .lb-note.small{ margin:8px 0 0; font-size:11.5px; }
.lobby .lb-note.warn{
  display:flex; align-items:flex-start; gap:8px; color:#ffdf9a;
}
.lobby .ci{ display:inline-block; width:1em; height:1em; flex:none; vertical-align:-.15em; }
.lobby .lb-lab .ci,
.lobby .lb-note .ci{ width:14px; height:14px; color:var(--aqua); }
.lobby .lb-note.warn .ci{ color:var(--gold); }
.lobby .ci svg{ width:100%; height:100%; display:block; }

.lobby .pill{ display:inline-flex; align-items:center; gap:7px; }
.lobby .pill .ci{ width:14px; height:14px; }
.lobby .btn .ico{ padding:0; display:grid; place-items:center;
  background:linear-gradient(180deg,#3a63ad,#16305f); color:#dff6ff; border-radius:0;
  clip-path:polygon(6px 0,100% 0,100% calc(100% - 6px),calc(100% - 6px) 100%,0 100%,0 6px);
  box-shadow:inset 0 0 0 2px rgba(0,0,0,.45), inset 0 2px 0 rgba(255,255,255,.16); }
.lobby .btn .ico svg{ display:block; }
.lobby .btn .chev{ width:15px; height:15px; display:block; flex:none; }
.lobby .btn .chev svg{ width:100%; height:100%; display:block; }
.lobby .btn.wide{ width:100%; }
.lobby .btn.wide.small{ padding:9px 16px 9px 10px; font-size:12px; }
.lobby .btn.wide.small .ico{ width:24px; height:24px; }
.lobby .btn.wide .hd-r{ font:800 10px/1 var(--ui); letter-spacing:.12em; color:var(--aqua-hi); }
.lobby .btn.back{ padding:9px 16px; font-size:13px; flex:none;
  clip-path:polygon(16px 0,100% 0,100% 100%,16px 100%,0 50%); }
.lobby .btn.back svg{ transform:rotate(180deg); }
/* two secondary CTAs that are not the one gold thing on the screen */
.lobby .btn.gold-ish{ background:linear-gradient(180deg,#2c5aa8,#16305f); }
.lobby .btn.gold-ish:hover{ background:linear-gradient(180deg,#3a6dc4,#1c3d76); }
.lobby .btn.hot-ish{ background:linear-gradient(180deg,#c8206a,#7d0d41); }
.lobby .btn.hot-ish:hover{ background:linear-gradient(180deg,#e2317f,#94104e); }

/* ── inputs ──────────────────────────────────────────────── */
.lobby .lb-input{
  width:100%; padding:11px 13px; border:0; color:var(--ink);
  background:linear-gradient(180deg,#08122b,#0c1a38);
  font:800 15px/1 var(--ui); letter-spacing:.06em;
  box-shadow:inset 0 0 0 2px var(--outline), inset 0 2px 6px rgba(0,0,0,.5);
}
.lobby .lb-input.code{
  font:900 21px/1 var(--display); letter-spacing:.13em; color:var(--aqua-hi);
  text-transform:uppercase;
}
.lobby .lb-input::placeholder{ color:#7fa1bd; }   /* 5.5:1 on the field */
.lobby .lb-input:focus{ outline:3px solid #8ff9ee; outline-offset:2px; }
.lobby .lb-codefield{ display:flex; gap:9px; align-items:stretch; }
.lobby .lb-codefield .lb-input{ flex:1; min-width:0; }
.lobby .lb-codefield .pill{ flex:none; }

/* native <select> — keyboard-perfect for free, restyled to the
   chunky language and given its own chevron because the platform
   arrow ignores every colour on this page */
.lobby .lb-field{ margin-bottom:9px; }
.lobby .lb-selwrap{ position:relative; }
.lobby .lb-sel{
  width:100%; appearance:none; -webkit-appearance:none; border:0;
  padding:10px 34px 10px 12px; cursor:pointer; color:var(--ink);
  background:linear-gradient(180deg,#1f3c72,#132549);
  font:800 12.5px/1.15 var(--ui); letter-spacing:.08em;
  box-shadow:inset 0 0 0 2px var(--outline), 0 3px 0 rgba(3,6,16,.5);
}
.lobby .lb-sel option{ background:#12234d; color:var(--ink); }
.lobby .lb-sel:focus{ outline:3px solid #8ff9ee; outline-offset:2px; }
.lobby .lb-sel:disabled{ opacity:1; color:var(--lb-label); cursor:not-allowed;
  background:linear-gradient(180deg,#16264a,#0d1a35); }
.lobby .lb-chev{
  position:absolute; right:11px; top:50%; transform:translateY(-50%) rotate(90deg);
  width:14px; height:14px; pointer-events:none; color:var(--aqua);
}
.lobby .lb-sel:disabled + .lb-chev{ color:var(--ink-dim); }
.lobby .lb-chev svg{ width:100%; height:100%; display:block; }

/* ── the room code plate ─────────────────────────────────── */
.lobby .lb-code{
  display:flex; align-items:center; gap:10px; padding:11px 12px;
  background:linear-gradient(180deg,#08122b,#0c1a38);
  box-shadow:inset 0 0 0 2px var(--outline), inset 0 2px 8px rgba(0,0,0,.55);
}
.lobby .lb-code b{
  flex:1; min-width:0; font:900 clamp(20px,1.9vw,27px)/1 var(--display);
  letter-spacing:.06em; color:var(--aqua-hi);
  -webkit-text-stroke:3px var(--outline); paint-order:stroke fill;
}
.lobby .pill.ok{ background:linear-gradient(180deg,#9dff4d,#3f8f13); color:#0d2200; --edge:#d8ffb0; }
.lobby .pill.bad{ background:linear-gradient(180deg,#ff9ec4,#c01e5e); color:#3d0018; --edge:#ffd0e2; }
.lobby .btn.ok{ background:linear-gradient(180deg,#9dff4d,#3f8f13); color:#0d2200;
  text-shadow:0 1px 0 rgba(255,255,255,.3); }
.lobby .btn.bad{ background:linear-gradient(180deg,#ff9ec4,#c01e5e); color:#3d0018;
  text-shadow:0 1px 0 rgba(255,255,255,.3); }

/* ── the room list ───────────────────────────────────────── */
.lobby .grow-panel{ display:flex; flex-direction:column; }
.lobby .lb-rooms{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:8px; }
.lobby .lb-room{
  position:relative; width:100%; border:0; cursor:pointer; text-align:left;
  display:flex; align-items:center; gap:12px; padding:9px 12px;
  color:var(--ink); background:linear-gradient(180deg,#1c3667,#101f42);
  clip-path:polygon(10px 0,100% 0,100% calc(100% - 10px),calc(100% - 10px) 100%,0 100%,0 10px);
  --edge:var(--outline); --lift:0 3px 0 rgba(3,6,16,.55);
  filter:
    drop-shadow(2px 0 0 var(--edge))  drop-shadow(-2px 0 0 var(--edge))
    drop-shadow(0 2px 0 var(--edge))  drop-shadow(0 -2px 0 var(--edge))
    drop-shadow(var(--lift));
  transition:transform .12s cubic-bezier(.3,1.5,.5,1), background .12s;
}
.lobby .lb-room:hover{ transform:translateX(4px); background:linear-gradient(180deg,#244480,#152a54); }
.lobby .lb-room.full{ cursor:not-allowed; }
.lobby .lb-room.full:hover{ transform:none; }
.lobby .lr-ico{ width:30px; height:30px; flex:none; display:block; color:var(--aqua); }
.lobby .lr-ico svg{ width:100%; height:100%; display:block; }
.lobby .lb-room .lr-txt{ display:flex; flex-direction:column; gap:3px; min-width:0; flex:1; }
.lobby .lr-txt b{ font:900 14px/1.1 var(--display); letter-spacing:.04em;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.lobby .lr-txt em{ font:700 10.5px/1 var(--ui); font-style:normal; letter-spacing:.1em;
  color:var(--lb-label); }
.lobby .lr-n{ flex:none; font:900 17px/1 var(--display); color:var(--lime); }
.lobby .lr-n i{ font:800 12px/1 var(--ui); font-style:normal; color:var(--lb-label); }
.lobby .lb-room.full .lr-n{ color:var(--lb-rose); }
.lobby .lr-state{ width:17px; height:17px; flex:none; display:block; color:var(--aqua); }
.lobby .lr-state svg{ width:100%; height:100%; display:block; }
/* The mode families from theme.css, reused so a room row and a mode
   card read as the same taxonomy — but lifted off theme's --violet
   (2.8:1) and --hot (3.7:1), because here the family colour also
   paints the mode NAME, and a name is text. */
.lobby .m-cla{ color:#dff7ff; } .lobby .m-sab{ color:var(--aqua); }
.lobby .m-cha{ color:#c9a8ff; } .lobby .m-ars{ color:var(--gold); }
.lobby .m-mae{ color:var(--lb-rose); } .lobby .m-pow{ color:var(--lime); }

/* ── honest notes ────────────────────────────────────────── */
.lobby .lb-facts{ list-style:none; margin:0; padding:0; display:flex;
  flex-direction:column; gap:9px; }
.lobby .lb-facts li{ display:flex; align-items:flex-start; gap:9px;
  font:600 12px/1.5 var(--ui); color:var(--lb-note); }
.lobby .lb-facts .ci{ width:15px; height:15px; margin-top:1px; }
.lobby .lb-facts .ci.ok{ color:var(--lime); }
.lobby .lb-facts .ci.warn{ color:var(--lb-rose); }

.lobby .lb-quick{ width:100%; padding:15px 26px 15px 18px; font-size:clamp(20px,2vw,28px); }
.lobby .btn.play .play-tri{ width:clamp(24px,2.6vw,34px); height:clamp(24px,2.6vw,34px);
  flex:none; display:block; }
.lobby .btn.play .play-tri svg{ width:100%; height:100%; display:block; }

.lobby .lb-mascot{
  margin:2px auto -10px; width:min(100%,240px); aspect-ratio:560/690;
  filter:drop-shadow(0 14px 20px rgba(0,0,0,.6)); pointer-events:none;
}
.lobby .lb-mascot svg{ width:100%; height:100%; display:block; }

/* ═══ THE RING ═══════════════════════════════════════════════
   The signature shape of the reference: the roster seated around
   the arena. Angles are computed in lobby.js so 2 through 8 walls
   all space evenly; this only has to hold the badges. */
.lobby .lb-ring{
  position:relative; width:100%;
  flex:1 1 auto; min-height:330px; max-height:min(68vh,620px); margin:0 auto;
  container-type:inline-size;
}
.lobby .lb-table{
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width:32%; min-width:150px; padding:16px 10px 13px;
  display:flex; flex-direction:column; align-items:center; gap:5px; text-align:center;
  background:linear-gradient(180deg,rgba(16,34,74,.82),rgba(6,13,32,.86));
  clip-path:polygon(24% 0,76% 0,100% 30%,100% 70%,76% 100%,24% 100%,0 70%,0 30%);
  box-shadow:0 0 34px rgba(47,230,214,.16);
}
.lobby .lt-mark{ width:44px; height:44px; display:block; color:var(--aqua); }
.lobby .lt-mark svg{ width:100%; height:100%; display:block; stroke-width:34;
  filter:drop-shadow(0 0 7px rgba(47,230,214,.75)); }
.lobby .lb-table b{ font:900 15px/1 var(--display); letter-spacing:.07em; color:var(--aqua-hi);
  -webkit-text-stroke:3px var(--outline); paint-order:stroke fill; }
.lobby .lb-table em{ font:800 9px/1.3 var(--ui); font-style:normal; letter-spacing:.14em;
  color:#ffdf9a; }

.lobby .lb-seat{
  position:absolute; transform:translate(-50%,-50%);
  width:clamp(104px,13cqw,132px); padding:8px 6px 7px;
  display:flex; flex-direction:column; align-items:center; gap:3px; text-align:center;
  background:linear-gradient(180deg,#16294f,var(--lb-plate));
  clip-path:polygon(11px 0,calc(100% - 11px) 0,100% 11px,100% calc(100% - 11px),
                    calc(100% - 11px) 100%,11px 100%,0 calc(100% - 11px),0 11px);
  --edge:var(--seat,#7aa0c8); --lift:0 4px 0 rgba(3,6,16,.6);
  /* The reference wraps every neon form in black — so the chain runs
     TWICE: four shadows in the seat colour grow the silhouette by
     2.5px, then four in the outline colour wrap that ring in a hard
     dark edge. Order matters; each pass sees the previous result.

     PERF, measured: eleven chained drop-shadows across eight badges
     costs nothing at rest (60fps idle, 16.7ms frames) but 20fps if
     all eight are invalidated every frame. So DO NOT ANIMATE THESE.
     Ready state, host crown and seat colour are static states that
     repaint on a roster change, which is a click, not a frame. If you
     ever want a pulsing ready badge, animate a cheap unfiltered child
     — never this element. */
  filter:
    drop-shadow(2.5px 0 0 var(--edge))  drop-shadow(-2.5px 0 0 var(--edge))
    drop-shadow(0 2.5px 0 var(--edge))  drop-shadow(0 -2.5px 0 var(--edge))
    drop-shadow(2px 0 0 var(--outline)) drop-shadow(-2px 0 0 var(--outline))
    drop-shadow(0 2px 0 var(--outline)) drop-shadow(0 -2px 0 var(--outline))
    drop-shadow(var(--lift)) drop-shadow(0 10px 18px rgba(0,0,0,.55))
    drop-shadow(var(--glow,0 0 0 transparent));
}
/* NOT a box-shadow: clip-path clips the element's whole rendering,
   its outer shadow included, so a halo has to come off the filter
   chain like everything else on this screen. */
.lobby .lb-seat.rdy{ --glow:0 0 11px var(--seat); }
.lobby .lb-seat.me{ background:linear-gradient(180deg,#25417a,#0b142f); }
.lobby .ls-n{
  position:absolute; left:-9px; top:-9px; width:26px; height:26px;
  display:grid; place-items:center; background:var(--seat,#7aa0c8); color:#08111f;
  font:900 14px/1 var(--display);
  clip-path:polygon(50% 0,100% 27%,100% 73%,50% 100%,0 73%,0 27%);
  box-shadow:0 0 0 2px var(--outline);
}
.lobby .ls-crown{ position:absolute; right:-6px; top:-12px; width:22px; height:22px; display:block; }
.lobby .ls-crown svg{ width:100%; height:100%; display:block; }
.lobby .ls-face{
  width:clamp(44px,5.4cqw,56px); height:clamp(44px,5.4cqw,56px); display:block;
  border-radius:50%; overflow:hidden; padding:3px;
  background:radial-gradient(circle at 38% 30%, #16294f, #060c1c);
  box-shadow:0 0 0 2.5px var(--outline), 0 0 0 5px var(--seat,#7aa0c8),
             0 3px 0 rgba(0,0,0,.5);
}
.lobby .ls-face svg{ width:100%; height:100%; display:block; }
.lobby .ls-name{
  font:900 12px/1.1 var(--display); letter-spacing:.04em; color:var(--ink);
  -webkit-text-stroke:2.6px var(--outline); paint-order:stroke fill;
  max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.lobby .ls-state{
  display:flex; align-items:center; gap:4px;
  font:800 9px/1 var(--ui); letter-spacing:.1em; color:var(--lb-rose);
}
.lobby .ls-state .ci{ width:11px; height:11px; }
.lobby .lb-seat.rdy .ls-state{ color:var(--lime); }

/* ── an OPEN seat ─────────────────────────────────────────────
   A room is `slots` walls wide the moment it is made, and the seats
   nobody has taken are drawn rather than left out — a ring that
   shrinks to the two people in it tells a host their eight-wall room
   is a two-wall room.

   It has to read as WAITING, not as BROKEN or as a failed render, and
   the difference is almost entirely in the edge: a solid neon ring is
   how this screen says "somebody is here", so an empty seat gets a
   DASHED one in the label slate instead, on a flatter, darker plate,
   with no crown, no ready badge and no glow. It keeps the same
   silhouette and the same numbered chip so the count is still legible
   at a glance.

   The dashed edge is a border on an inner pseudo-element, NOT on the
   seat itself: `clip-path` on .lb-seat cuts its own border off at the
   corners (trap 1 in this file's header — the same stacking rule),
   and the filter chain can only draw solid rings. `::after` sits
   INSIDE the clip and is free to be dashed. */
.lobby .lb-seat.open{
  --seat:#43608c;                       /* the edge chain reads this */
  --lift:0 3px 0 rgba(3,6,16,.5);
  background:linear-gradient(180deg,#0d1734,#070c1e);
}
.lobby .lb-seat.open::after{
  content:""; position:absolute; inset:4px; pointer-events:none;
  border:2px dashed rgba(169,199,221,.42);
}
.lobby .lb-seat.open .ls-n{ background:#43608c; color:#d6e6f5; }
.lobby .lb-seat.open .ls-face{
  color:var(--lb-label);
  background:radial-gradient(circle at 38% 30%, #12203f, #050a17);
  box-shadow:0 0 0 2.5px var(--outline), 0 0 0 5px #43608c, 0 3px 0 rgba(0,0,0,.5);
  padding:12px;                         /* the + is a glyph, not a face */
}
.lobby .lb-seat.open .ls-name{ color:var(--lb-label); }
.lobby .lb-seat.open .ls-state{ color:var(--lb-label); }

/* ── TEAMS: saying which arc a seat is on ─────────────────────
   The sim splits the ring into two CONTIGUOUS ARCS — side A from
   seat 0, side B straight after — which is the right shape (your
   team is beside you) and is completely unreadable as a diagram:
   eight chips in a circle look like eight chips in a circle,
   whichever four you meant. Colour alone does not carry it either;
   the ring is already eight different colours by default and a
   player has no reason to know that teal and lime are "the cool
   family".

   So each seat WEARS ITS SIDE'S NAME, in its side's colour, above
   the face. `--seat` on the seat is already the team hex in a TEAMS
   room (lobby.js `_ring` swaps it), so the badge, the numbered chip
   and the edge chain all recolour together with no second variable.

   `order:-1` rather than a different DOM position: the seat is a
   column flexbox and the badge belongs at the top, but the numbered
   chip and the crown are absolutely positioned siblings that must
   keep their document order for the focus ring. */
.lobby .ls-team{
  order:-1; flex:none; max-width:100%; margin-bottom:1px;
  padding:2px 8px 3px; color:#08111f; background:var(--seat,#7aa0c8);
  font:900 8.5px/1 var(--ui); letter-spacing:.14em; text-transform:uppercase;
  clip-path:polygon(4px 0,100% 0,calc(100% - 4px) 100%,0 100%);
  box-shadow:0 0 0 2px var(--outline);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
/* an open seat still belongs to a side — it is the wall a bot will
   take at START — but it must not shout as loudly as a person */
.lobby .lb-seat.open .ls-team{ opacity:.6; }
/* SHUFFLED: the arrangement is a function of the match seed and there
   is no seed until START, so no seat may claim a side yet. Neutral
   ink rather than a side colour, because a colour here would be a
   guess and this chip's whole job is to say it is not one. */
.lobby .ls-team.tbd{
  background:rgba(255,255,255,.16); color:var(--ink);
  letter-spacing:.10em;
}

/* the same fact in the roster table, beside the name */
.lobby .team-tag{
  flex:none; padding:3px 7px; color:#08111f; background:var(--seat,#7aa0c8);
  font:900 9px/1 var(--ui); letter-spacing:.12em; text-transform:uppercase;
  clip-path:polygon(5px 0,100% 0,calc(100% - 5px) 100%,0 100%);
  box-shadow:0 0 0 2px var(--outline);
}
.lobby tr.seat.open .team-tag{ opacity:.6; }
.lobby .team-tag.tbd{ background:rgba(255,255,255,.16); color:var(--ink); }

/* the two dots under the TEAMS control — the colours the match will
   actually paint, set inline from OP.TEAM_COLORS */
.lobby .lb-teamnote .lb-tdot{
  display:inline-block; width:9px; height:9px; margin:0 4px -1px 0;
  box-shadow:0 0 0 2px var(--outline);
}

/* ── your controls, under the ring ───────────────────────── */
.lobby .lb-self{
  display:flex; align-items:flex-end; gap:16px; flex-wrap:wrap;
  justify-content:center; padding:4px 4px 2px;
}
.lobby .lb-swatches{ display:flex; flex-direction:column; gap:6px; }

/* ── your name ────────────────────────────────────────────────
   Same field in the browse view (set it before you make a room)
   and on the self bar inside the room (change it in front of the
   people who are about to read it). One rule set, two homes. */
.lobby .lb-namefield{ display:flex; gap:9px; align-items:stretch; }
.lobby .lb-namefield .lb-input{ flex:1; min-width:0; letter-spacing:.06em; }
.lobby .lb-namefield .pill{ flex:none; }
/* the self bar is a centred row of blocks; give the name a sane
   column so it does not stretch the whole bar on a wide screen */
.lobby .lb-self .lb-name{ display:flex; flex-direction:column; gap:6px;
  min-width:220px; max-width:300px; text-align:left; }
.lobby .lb-self .lb-name .lb-note{ margin:0; }
/* the help paragraph is reference, not headline — it must not push the
   READY button off the bar */
.lobby .lb-self .lb-name .lb-note.small{ display:none; }
.lobby .lb-note code{ font-family:inherit; letter-spacing:.12em; opacity:.85; }
.lobby .sw-row{ display:flex; gap:7px; flex-wrap:wrap; }
.lobby .lb-swatch{
  position:relative; width:34px; height:34px; border:0; cursor:pointer; padding:0;
  display:grid; place-items:center; background:var(--seat);
  clip-path:polygon(50% 0,100% 27%,100% 73%,50% 100%,0 73%,0 27%);
  --edge:var(--outline); --lift:0 3px 0 rgba(3,6,16,.55);
  filter:
    drop-shadow(2px 0 0 var(--edge))  drop-shadow(-2px 0 0 var(--edge))
    drop-shadow(0 2px 0 var(--edge))  drop-shadow(0 -2px 0 var(--edge))
    drop-shadow(var(--lift));
  transition:transform .12s cubic-bezier(.3,1.5,.5,1);
}
.lobby .lb-swatch:hover{ transform:translateY(-3px); }
.lobby .lb-swatch.on{ --edge:#ffffff; transform:translateY(-3px) scale(1.06); }
/* a taken swatch is still readable AS a colour — dim it to the point
   where its owner is obvious and no further, or the picker stops
   telling you which colour you are being refused */
.lobby .lb-swatch.taken{ filter:
    drop-shadow(2px 0 0 var(--outline))  drop-shadow(-2px 0 0 var(--outline))
    drop-shadow(0 2px 0 var(--outline))  drop-shadow(0 -2px 0 var(--outline))
    saturate(.7) brightness(.78); cursor:not-allowed; }
.lobby .lb-swatch.taken:hover{ transform:none; }
.lobby .lb-swatch .ci{ width:14px; height:14px; }
.lobby .lb-ready{ padding:14px 30px 14px 20px; font-size:clamp(17px,1.7vw,23px); }
.lobby .lb-ready .play-tri{ width:26px; height:26px; }

/* ── mode panel ──────────────────────────────────────────── */
.lobby .lb-mode{ display:flex; align-items:flex-start; gap:12px; }
.lobby .lm-ico{ width:44px; height:44px; flex:none; display:block; color:currentColor;
  filter:drop-shadow(0 0 12px currentColor); }
.lobby .lm-ico svg{ width:100%; height:100%; display:block; }
.lobby .lb-mode h3{
  margin:0 0 5px; font:900 clamp(19px,1.8vw,25px)/1 var(--display); letter-spacing:.03em;
  color:currentColor; -webkit-text-stroke:3px var(--outline); paint-order:stroke fill;
}
.lobby .lb-mode p{ margin:0; font:600 12px/1.5 var(--ui); color:var(--lb-note); }
.lobby .lb-rules{ list-style:none; margin:12px 0 0; padding:11px 0 0; display:flex;
  flex-direction:column; gap:7px; border-top:2px solid var(--lb-line); }
.lobby .lb-rules li{ display:flex; align-items:center; gap:9px;
  font:700 12px/1.35 var(--ui); color:var(--lb-note); }
.lobby .lb-rules .ci{ width:14px; height:14px; color:var(--lime); }

/* ── roster ──────────────────────────────────────────────────
   A deliberate sibling of the FINAL STANDINGS table in results.css:
   same tinted per-seat rows, same rank chip, same gold bar for the
   local player. Two screens, one product. */
.lobby .lb-table-wrap{
  overflow:auto; max-height:min(54vh,478px); margin:0 -3px; padding:0 3px;
  scrollbar-width:thin; scrollbar-color:#2c4a86 transparent;
}
.lobby .lb-table-wrap::-webkit-scrollbar{ width:9px; }
.lobby .lb-table-wrap::-webkit-scrollbar-thumb{ background:#2c4a86; border-radius:99px; }
.lobby .lb-table-wrap:focus{ outline:3px solid #8ff9ee; outline-offset:2px; }

table.lb-roster{ width:100%; border-collapse:separate; border-spacing:0 6px;
  font:800 13px/1 var(--ui); }
table.lb-roster thead th{
  position:sticky; top:0; z-index:2; padding:5px 9px 7px; text-align:right; white-space:nowrap;
  background:linear-gradient(180deg,#16295a,#12234d);
  font:800 10px/1.2 var(--ui); letter-spacing:.14em; text-transform:uppercase;
  color:var(--lb-label);
}
table.lb-roster thead th:nth-child(1){ text-align:center; width:48px; }
table.lb-roster thead th:nth-child(2){ text-align:left; }
table.lb-roster thead th:nth-child(4){ width:34px; }
table.lb-roster tbody td{
  padding:7px 9px; background:var(--lb-row); text-align:right; white-space:nowrap;
  color:var(--ink); text-shadow:0 1px 0 rgba(0,0,0,.55);
  border-top:2px solid var(--outline); border-bottom:2px solid var(--outline);
}
table.lb-roster tbody td:first-child{ border-left:2px solid var(--outline);
  width:48px; text-align:center; }
table.lb-roster tbody td:last-child{ border-right:2px solid var(--outline); padding-left:0; }
table.lb-roster tbody td.name{ text-align:left; width:99%; }
/* a FLAT tint, not a gradient: `background` paints per-cell, so a
   left-to-right wash restarts in every column and the row stripes */
table.lb-roster tbody tr.seat td{
  background:linear-gradient(0deg, var(--seat-wash), var(--seat-wash)), var(--lb-row); }
table.lb-roster tbody tr.seat td:first-child{ box-shadow:inset 5px 0 0 var(--seat); }

.lobby .rank-chip{
  display:inline-grid; place-items:center; width:28px; height:28px;
  background:linear-gradient(180deg,#2a4780,#16294f); color:var(--ink);
  font:900 14px/1 var(--display);
  clip-path:polygon(50% 0,100% 27%,100% 73%,50% 100%,0 73%,0 27%);
  box-shadow:0 0 0 2px var(--outline);
}
/* wrap is the load-bearing word. HOST and YOU are flex:none by design
   — they must never ellipsize into "HOS…" — so without wrapping they
   set an unshrinkable 161px floor on this column and the table could
   not fit its panel. Allowed to wrap, the cell's minimum drops to one
   tag and the tags drop under the name only when the panel is genuinely
   too narrow for both, which is the honest failure mode. */
.lobby .who-cell{ display:flex; align-items:center; flex-wrap:wrap;
  gap:4px 9px; min-width:0; }
.lobby .who-cell .dot{ width:16px; height:16px; flex:none; border-radius:50%;
  box-shadow:0 0 0 2px var(--outline); }
/* min-width:0 is what makes the ellipsis on the line below actually
   reachable. A flex item's automatic minimum is its min-content, so
   the name was an unshrinkable ~175px and the four columns summed to
   361px inside a 287px panel at 1280x720 — REMOVE and half of STATE
   lived behind a horizontal scrollbar the host had no reason to look
   for. The name is the right thing to shorten; HOST/YOU stay whole. */
.lobby .who-cell .nm{ font:900 14px/1.15 var(--display); letter-spacing:.03em;
  min-width:0; text-transform:uppercase; overflow:hidden; text-overflow:ellipsis; }
.lobby .who-cell .pn{ flex:none; font:700 10px/1.2 var(--ui); letter-spacing:.1em;
  color:var(--lb-label); text-transform:uppercase; }
.lobby .host-tag,.lobby .you-tag{
  flex:none; padding:3px 7px; font:900 9.5px/1 var(--ui); letter-spacing:.13em;
  clip-path:polygon(5px 0,100% 0,calc(100% - 5px) 100%,0 100%);
  box-shadow:0 0 0 2px var(--outline);
}
.lobby .host-tag{ background:linear-gradient(180deg,var(--aqua),var(--aqua-lo)); color:#05221f; }
.lobby .you-tag{ background:linear-gradient(180deg,var(--gold),var(--gold-lo)); color:#2a1500; }
/* the other half of the same fix: "BOT AT START" held a 120px nowrap
   column open. Two short lines cost nothing and give it back. */
.lobby .st-cell{ padding-right:6px; white-space:normal; }
.lobby .st-cell .rdy{ text-align:right; }
.lobby .rdy{ display:inline-flex; align-items:center; gap:5px;
  font:800 10.5px/1 var(--ui); letter-spacing:.1em; }
.lobby .rdy .ci{ width:13px; height:13px; }
.lobby .rdy.on{ color:var(--lime); }
.lobby .rdy.off{ color:var(--lb-rose); }
/* the roster table's half of the open seat: a row, deliberately
   quieter than an occupied one, with a hollow dot where the seat
   colour would be. No seat colour is claimed because nobody has
   claimed one — colours stay exclusive and an empty chair holds none. */
.lobby .rdy.open{ color:var(--lb-label); }
table.lb-roster tbody tr.seat.open td{ background:#0b1734; color:var(--lb-label); }
table.lb-roster tbody tr.seat.open td:first-child{ box-shadow:inset 5px 0 0 #43608c; }
table.lb-roster tbody tr.seat.open .rank-chip{
  background:linear-gradient(180deg,#1b2f56,#101d3c); color:var(--lb-label); }
.lobby .who-cell .dot.open{ background:transparent;
  box-shadow:0 0 0 2px var(--outline), inset 0 0 0 2px #5c7ba8; }
.lobby .lb-kick{
  width:24px; height:24px; border:0; cursor:pointer; display:grid; place-items:center;
  background:linear-gradient(180deg,#ff7ab5,#c01e5e); color:#3d0018;
  clip-path:polygon(50% 0,100% 27%,100% 73%,50% 100%,0 73%,0 27%);
  box-shadow:0 0 0 2px var(--outline); transition:transform .12s;
}
.lobby .lb-kick:hover{ transform:scale(1.12); }
.lobby .lb-kick svg{ display:block; }

/* your row — the one gold bar on the table, same as results.css */
table.lb-roster tbody tr.me td{
  background:linear-gradient(180deg,#ffd766,#e9a72c); color:#2a1500;
  text-shadow:0 1px 0 rgba(255,255,255,.35);
  border-top-color:#7a4a00; border-bottom-color:#7a4a00;
}
table.lb-roster tbody tr.me td:first-child{ border-left-color:#7a4a00;
  box-shadow:inset 5px 0 0 var(--seat); }
table.lb-roster tbody tr.me td:last-child{ border-right-color:#7a4a00; }
tr.me .rank-chip{ background:linear-gradient(180deg,#2a1500,#150a00); color:var(--gold-hi);
  box-shadow:0 0 0 2px #7a4a00; }
tr.me .you-tag{ background:linear-gradient(180deg,#3b1e00,#1f0f00); color:var(--gold-hi);
  box-shadow:0 0 0 2px #7a4a00; }
tr.me .host-tag{ background:linear-gradient(180deg,#0b3a36,#052421); color:#7ff5ea;
  box-shadow:0 0 0 2px #7a4a00; }
tr.me .rdy.on{ color:#0d3b00; }         /* 7.6:1 on the gold bar */
tr.me .rdy.off{ color:#5c0026; }        /* 6.1:1 on the gold bar */

/* ── start ───────────────────────────────────────────────────
   PINNED, because it is the primary action and it was not findable.
   START is the last block of the right-hand column, under MODE,
   ROSTER and CHAT. At 1280x720 — the commonest laptop shape there is
   — that column is 1208px of content in a 620px box, so START MATCH
   landed at y=1154: 434px BELOW THE FOLD, behind a thin inner
   scrollbar, on the one screen where the host is looking for exactly
   one button. Sticky rather than a restack: the column keeps its
   reading order (who is here, what they are saying, then go), and the
   button rides the bottom of whichever scrollport it is in — .lb-col
   in the three-column layout, .lb-body once the columns collapse.
   The gradient is what stops chat scrolling out from under it
   looking like a rendering fault. */
.lobby .lb-start{
  display:flex; flex-direction:column; gap:6px;
  position:sticky; bottom:0; z-index:4;
  margin-top:auto; padding:10px 0 2px;
  background:linear-gradient(180deg,
    rgba(6,12,30,0) 0, rgba(6,12,30,.86) 22%, rgba(6,12,30,.94) 100%);
}
.lobby .lb-start .btn.play{ padding:16px 34px 16px 22px;
  font-size:clamp(19px,1.9vw,26px); justify-content:flex-start; }
/* Not ready yet: the gold is banked down so it stops competing with
   a live CTA, but it is still pressable and still says why — a
   disabled primary with no explanation is the same as a dead one.
   The ramp is dark enough that the label holds 5.6:1, not the 3.8:1
   a straight tint of the gold gives. */
.lobby .lb-start .btn.play.cold{
  background:linear-gradient(180deg,#75612c,#4a3c15); color:#fff6dc;
  text-shadow:0 2px 0 rgba(0,0,0,.55);
  filter:drop-shadow(0 6px 0 rgba(3,6,16,.6));
}
.lobby .lb-start .btn.play.cold:hover{ background:linear-gradient(180deg,#8a7335,#5b4a1b); }
.lobby .lb-start .btn.waiting{
  cursor:default; background:linear-gradient(180deg,#1c3667,#101f42); color:var(--ink);
}
.lobby .lb-start .btn.play.waiting{
  background:linear-gradient(180deg,var(--gold-hi),var(--gold),var(--gold-lo)); color:#2a1500;
}
.lobby .lb-start .lb-note{ margin:0; text-align:center; }

/* ── status strip ────────────────────────────────────────── */
.lobby .lb-status{
  zoom:var(--op-ui-scale,1); flex-wrap:wrap; gap:14px 18px;
  /* theme.css paints this with --ink-faint, which measures 3.1:1 on
     the lighter ground behind it. This screen carries real sentences
     down here, so it gets a passing colour. */
  color:var(--lb-label);
}
.lobby .lb-status .st{ display:inline-flex; align-items:center; gap:7px; }
.lobby .lb-status .st i{ width:15px; height:15px; display:block; color:var(--aqua); flex:none; }
.lobby .lb-status .st i svg{ width:100%; height:100%; display:block; }
.lobby .lb-status .st.ok{ color:var(--lime); } .lobby .lb-status .st.ok i{ color:var(--lime); }
.lobby .lb-status .st.warn{ color:var(--gold); } .lobby .lb-status .st.warn i{ color:var(--gold); }
.lobby .lb-status b{ color:var(--ink); font-weight:800; }
.lobby .lb-say{
  margin:0; text-align:right; min-height:14px; max-width:52ch;
  font:800 11px/1.4 var(--ui); letter-spacing:.08em; text-transform:uppercase;
  color:var(--gold-hi);
}

/* ═══ THE ARENA PICKER ═══════════════════════════════════════
   Five 480x270 captures at ~32 KB each. The one in use loads eagerly
   and the rest are `loading="lazy"`, so a room nobody re-arenas pays
   for one image — and every chip has its own `swatch` gradient from
   arenas.js underneath, which means the row is already legible and
   already tells five places apart before a single JPEG lands. Same
   two-fallbacks-under-the-shot idea as select.css, deliberately. */
.lobby .lb-arenas{
  display:grid; grid-template-columns:repeat(auto-fill,minmax(88px,1fr));
  gap:7px; margin:2px 0 10px;
}
.lobby .lb-arena{
  position:relative; border:0; padding:0; cursor:pointer; overflow:hidden;
  display:flex; flex-direction:column; text-align:left;
  background:var(--ar-sw,linear-gradient(160deg,#08122c,#1f7f8f));
  clip-path:polygon(7px 0,100% 0,100% calc(100% - 7px),calc(100% - 7px) 100%,0 100%,0 7px);
  box-shadow:inset 0 0 0 2px var(--outline);
  transition:transform .12s cubic-bezier(.3,1.5,.5,1);
}
.lobby .lb-arena:hover:not(:disabled){ transform:translateY(-3px); }
.lobby .la-shot{ display:block; aspect-ratio:16/9; overflow:hidden; }
.lobby .la-shot img{ width:100%; height:100%; display:block; object-fit:cover; }
.lobby .la-name{
  padding:5px 7px 6px; font:900 9.5px/1.15 var(--display); letter-spacing:.05em;
  color:var(--ink); background:linear-gradient(180deg,rgba(6,13,32,.55),rgba(6,13,32,.92));
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.lobby .lb-arena.on{ box-shadow:inset 0 0 0 3px var(--ar,var(--aqua)),
  inset 0 0 0 5px var(--outline); }
.lobby .lb-arena.on .la-name{ color:var(--ar,var(--aqua-hi)); }
.lobby .la-tick{
  position:absolute; right:4px; top:4px; width:20px; height:20px;
  display:grid; place-items:center; background:var(--ar,var(--aqua));
  clip-path:polygon(50% 0,100% 27%,100% 73%,50% 100%,0 73%,0 27%);
  box-shadow:0 0 0 2px var(--outline);
}
.lobby .la-tick svg{ display:block; }
/* A guest sees the host's pick and cannot change it. Dimmed to the
   point where the choice is still legible and no further — the row is
   there to TELL them where they are playing. */
.lobby .lb-arena:disabled{ cursor:not-allowed; filter:saturate(.75) brightness(.82); }
.lobby .lb-arena:disabled.on{ filter:none; }

/* ═══ THE CAST, IN THE ROOM ══════════════════════════════════
   240px webp chips, and only ever those — see roster.js. The grid is
   behind a disclosure in lobby.js so the sixteen are not fetched for
   a player who never opens it. */
.lobby .lb-charbox{ display:flex; flex-direction:column; gap:6px; }
.lobby .lb-charnow{ display:flex; align-items:center; gap:10px; }
.lobby .lb-charart{
  width:52px; height:52px; flex:none; display:block; border-radius:50%;
  object-fit:cover; background:radial-gradient(circle at 38% 30%,#16294f,#060c1c);
  box-shadow:0 0 0 2.5px var(--outline), 0 0 0 5px var(--tint,var(--aqua));
}
.lobby .lb-chartxt{ display:flex; flex-direction:column; gap:5px; align-items:flex-start; }
.lobby .lb-chartxt em{
  font:800 9.5px/1 var(--ui); font-style:normal; letter-spacing:.12em;
  color:var(--lb-label); text-transform:uppercase;
}
.lobby .btn.sm{ padding:7px 12px; font-size:11px; letter-spacing:.1em; }
.lobby .btn.sm .ci{ width:14px; height:14px; }
.lobby .lb-cast{
  display:grid; grid-template-columns:repeat(auto-fill,minmax(58px,1fr));
  gap:6px; max-height:206px; overflow:auto; padding:4px 3px;
  scrollbar-width:thin; scrollbar-color:#2c4a86 transparent;
}
.lobby .lb-cast::-webkit-scrollbar{ width:9px; }
.lobby .lb-cast::-webkit-scrollbar-thumb{ background:#2c4a86; border-radius:99px; }
.lobby .lb-face{
  position:relative; border:0; padding:3px 2px 4px; cursor:pointer;
  display:flex; flex-direction:column; align-items:center; gap:3px;
  background:linear-gradient(180deg,#16294f,var(--lb-plate));
  clip-path:polygon(6px 0,100% 0,100% calc(100% - 6px),calc(100% - 6px) 100%,0 100%,0 6px);
  box-shadow:inset 0 0 0 2px var(--outline);
  transition:transform .12s cubic-bezier(.3,1.5,.5,1);
}
.lobby .lb-face img{ width:40px; height:40px; display:block; object-fit:cover; }
.lobby .lb-face .lf-n{
  font:900 7.5px/1 var(--display); letter-spacing:.03em; color:var(--lb-label);
  max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.lobby .lb-face:hover{ transform:translateY(-3px); }
.lobby .lb-face.on{ box-shadow:inset 0 0 0 3px var(--tint,var(--aqua)),
  inset 0 0 0 5px var(--outline); }
.lobby .lb-face.on .lf-n{ color:var(--tint,var(--aqua-hi)); }

/* the ring's seat portrait — an <img> where there used to be an SVG.
   `.ls-face` already sizes and rings it; this only has to fill it. */
.lobby .ls-face img.ls-art{ width:100%; height:100%; display:block; object-fit:cover;
  border-radius:50%; }
/* a bot wears a face derived from its SEAT, so it is the same face on
   every client — drawn back so it never reads as a person */
.lobby .ls-face img.ls-art.bot{ filter:saturate(.45) brightness(.82); }

/* ═══ CHAT ═══════════════════════════════════════════════════
   Every line here is written by another person. The panel renders all
   of it through esc() in lobby.js — there is no innerHTML path into
   the log — so this file only has to make it readable. Nothing here
   sizes from message content: a wall of text scrolls inside the log
   rather than growing the column. */
.lobby .lb-chat{ display:flex; flex-direction:column; }
.lobby .lb-chatlog{
  list-style:none; margin:0 0 9px; padding:8px 9px;
  display:flex; flex-direction:column; gap:6px;
  height:clamp(120px,20vh,210px); overflow-y:auto; overflow-x:hidden;
  background:var(--lb-row); box-shadow:inset 0 0 0 2px var(--outline);
  scrollbar-width:thin; scrollbar-color:#2c4a86 transparent;
}
.lobby .lb-chatlog::-webkit-scrollbar{ width:9px; }
.lobby .lb-chatlog::-webkit-scrollbar-thumb{ background:#2c4a86; border-radius:99px; }
.lobby .lb-chatlog:focus{ outline:3px solid #8ff9ee; outline-offset:2px; }
.lobby .lb-chatlog .cm{
  display:block; font:600 12px/1.45 var(--ui); color:var(--ink);
  /* the one property that stops a 160-character word being a
     horizontal scrollbar across somebody else's panel */
  overflow-wrap:anywhere; word-break:break-word;
}
.lobby .lb-chatlog .cn{
  display:inline-block; margin-right:7px; font:900 11px/1.2 var(--display);
  letter-spacing:.04em; color:var(--seat,var(--aqua-hi)); text-transform:uppercase;
  -webkit-text-stroke:2px var(--outline); paint-order:stroke fill;
}
.lobby .lb-chatlog .cm.me .cb{ color:#ffe9b4; }
/* A system line is flagged by the RELAY, never by the message body,
   so a player cannot forge one by choosing a clever name. It gets a
   visibly different shape as well as a different colour. */
.lobby .lb-chatlog .cm.sys{
  font:800 10px/1.4 var(--ui); letter-spacing:.1em; text-transform:uppercase;
  color:var(--lb-label); padding-left:9px; box-shadow:inset 3px 0 0 var(--aqua-lo);
}
.lobby .lb-chatbar{ display:flex; gap:8px; align-items:stretch; }
.lobby .lb-chatbar .lb-input{ flex:1; min-width:0; letter-spacing:.03em;
  text-transform:none; font-size:12.5px; }
.lobby .lb-chatbar .pill{ flex:none; }
.lobby .lb-chat .lb-note.small{ margin-top:7px; }

/* ── focus. clip-path eats `outline`, so light up the edge. ──
   :focus, not :focus-visible — Chrome leaves focus-visible false when
   focus moves by keyboard after a click, which hides the current item
   and made the whole shell keyboard-invisible once already. */
.lobby :is(.btn,.pill,.lb-room,.lb-swatch,.lb-kick,.lb-arena,.lb-face):focus{
  outline:none; --edge:#8ff9ee;
  box-shadow:inset 0 0 0 3px #8ff9ee, inset 0 0 0 7px rgba(2,8,18,.92);
  filter:
    drop-shadow(3px 0 0 var(--edge))  drop-shadow(-3px 0 0 var(--edge))
    drop-shadow(0 3px 0 var(--edge))  drop-shadow(0 -3px 0 var(--edge))
    drop-shadow(0 0 16px rgba(143,249,238,.95))
    drop-shadow(var(--lift));
}
/* the swatches are 34px: an inset ring that thick swallows the colour
   they exist to show, so they get the edge and a halo only */
.lobby .lb-swatch:focus{ box-shadow:none; transform:translateY(-3px) scale(1.1); }
.lobby .lb-kick:focus{ box-shadow:0 0 0 2px #8ff9ee; filter:none; outline:2px solid #8ff9ee;
  outline-offset:2px; }

/* ── accessibility flags, driven by the pause screen ─────── */
html.op-a11y-contrast .lobby::before{ background:rgba(3,5,14,.97); }
html.op-a11y-contrast .lobby .panel{ background:linear-gradient(180deg,#0f1f42,#060d22); }
html.op-a11y-contrast .lobby .btn::after{ display:none; }
html.op-a11y-contrast .lobby{ --lb-label:#dff7ff; --lb-note:#eaf8ff; --lb-row:#08132c; }

html.op-a11y-still .lobby *,
html.op-a11y-still .lobby *::before,
html.op-a11y-still .lobby *::after{ transition:none !important; animation:none !important; }
html.op-a11y-still .lobby .btn:hover,
html.op-a11y-still .lobby .lb-room:hover,
html.op-a11y-still .lobby .lb-arena:hover,
html.op-a11y-still .lobby .lb-face:hover,
html.op-a11y-still .lobby .lb-swatch:hover{ transform:none; }

@media (prefers-reduced-motion:reduce){
  .lobby *,.lobby *::before,.lobby *::after{ transition:none !important; animation:none !important; }
  .lobby .btn:hover,.lobby .lb-room:hover,.lobby .lb-swatch:hover,
  .lobby .lb-arena:hover,.lobby .lb-face:hover{ transform:none; }
}

/* ── narrow ──────────────────────────────────────────────── */
/* Two columns with the ring above them. The per-column scrollers have
   to go here: the mid column is tall and unscrollable by design, so
   leaving the others capped puts three independent scrollbars on one
   screen and hides the primary action. The page scrolls instead. */
@media (max-width:1240px){
  .lobby .lb-body.browse,
  .lobby .lb-body.room{ grid-template-columns:minmax(0,1fr) minmax(0,1fr); overflow:auto; }
  .lobby .lb-col{ max-height:none; overflow:visible; }
  .lobby .lb-col.mid{ grid-column:1 / -1; order:-1; }
  .lobby .lb-mascot{ display:none; }
}
@media (max-width:820px){
  .lobby .lb-body.browse,
  .lobby .lb-body.room{ grid-template-columns:minmax(0,1fr); overflow:auto; }
  .lobby .lb-col{ max-height:none; overflow:visible; }
  .lobby .lb-ring{ min-height:300px; }
  .lobby .lb-head{ padding:10px 14px 2px; }
  .lobby .lb-body{ padding:6px 14px; }
}
@media (max-height:760px){
  .lobby .lb-ring{ min-height:290px; max-height:44vh; }
  .lobby .lb-seat{ width:clamp(92px,12cqw,112px); padding:6px 5px 5px; }
}

/* ── touch targets ── see theme.css. The seat-colour hexes were 34px. */
@media (pointer:coarse){
  .lobby .lb-swatch{ width:44px; height:44px; }
}

/* ── YOUR TEAM ───────────────────────────────────────────────
   The one control on the settings panel that belongs to the player
   rather than the host, so it is deliberately a row of buttons and
   not another <select> — a dropdown here would read as one more
   host-owned, greyed-out field. */
.lb-tpicks{ display:flex; gap:7px; flex-wrap:wrap; min-width:0; }
.lb-tpick{
  display:inline-flex; align-items:center; gap:7px; white-space:nowrap;
  padding:8px 12px; font-size:11.5px; min-width:0;
}
.lb-tswatch{
  width:11px; height:11px; flex:none; background:var(--tm,#7ff5ea);
  box-shadow:0 0 0 2px var(--outline,#050814);
}
/* the picked side reads as picked without borrowing the gold that
   every other .pill.on uses for a host setting */
.lb-tpick.on{
  background:linear-gradient(180deg,#2b5cc4,#16306c);
  color:var(--ink,#f4fbff); --edge:var(--aqua,#7ff5ea);
}
.lb-tpick.on .lb-tswatch{ box-shadow:0 0 0 2px var(--outline,#050814), 0 0 0 4px rgba(255,255,255,.25); }
@media (max-width:520px){
  .lb-tpicks{ width:100%; }
  .lb-tpick{ flex:1 1 auto; justify-content:center; }
}

/* ── THE ROOM'S TEAMS, NAMED AND COLOURED HERE ───────────────
   The tuner's controls on the panel where the room is. One row per
   team: its number in its own colour, its name, its palette. */
.lb-tedits{ display:flex; flex-direction:column; gap:9px; min-width:0; }
.lb-tedit{
  display:grid; align-items:center; gap:9px; min-width:0;
  grid-template-columns:auto minmax(0,1fr);
  grid-template-areas:"num name" "sws sws";
  padding:9px 10px; background:rgba(6,12,28,.42);
  box-shadow:inset 0 0 0 2px rgba(3,6,16,.5);
}
.lb-tnum{
  grid-area:num; white-space:nowrap;
  font:900 10.5px/1 var(--ui); letter-spacing:.12em; color:var(--ink-dim);
  padding:6px 8px; background:rgba(6,12,28,.6);
  /* the team's own colour, which is the point of the row */
  border-left:4px solid var(--tm,#7ff5ea);
}
.lb-tname{ grid-area:name; min-width:0; width:100%; text-transform:uppercase; }
.lb-tsws{ grid-area:sws; display:flex; gap:5px; flex-wrap:wrap; align-items:center; }
.lb-tfam{ padding:6px 9px; font-size:10.5px; min-width:0; }
/* A SWATCH IS A PALETTE INDEX, not a colour picker — the sim recovers
   colorIdx by looking the hex up, and one it cannot find falls back
   to the seat number, detaching the colourblind glyph from its wall. */
.lb-tsw{
  width:26px; height:26px; padding:0; border:0; cursor:pointer; position:relative;
  background:rgba(6,12,28,.55); box-shadow:inset 0 0 0 2px rgba(3,6,16,.75);
  transition:transform var(--dur-fast,.14s) var(--ease-pop, cubic-bezier(.3,1.4,.5,1));
}
.lb-tsw i{ position:absolute; inset:4px; background:var(--tm); display:block; }
.lb-tsw:hover:not(:disabled){ transform:translateY(-2px); }
.lb-tsw.on{ box-shadow:inset 0 0 0 2px var(--gold,#ffc63d), 0 0 0 2px rgba(3,6,16,.75); }
.lb-tsw.on i{ inset:3px; }
.lb-tsw:disabled{ opacity:.26; cursor:not-allowed; }
@media (prefers-reduced-motion: reduce){
  .lb-tsw:hover:not(:disabled){ transform:none; }
}
