    /* ══════════════════════════════════════════════════════════════
       CUSTOM MATCH — entry control on the mode row (not a 4th radio)
       Not a .mode-card (quick-play.js owns those) and never amber:
       Quick Play is the only spend-weight surface on this rail. This is a
       chamfered STEEL chip — the same enclosure language as .squad-tab /
       .lb-refresh — so it reads as hardware you can press instead of a
       9px grey word that production players would never find.

       Modes + Custom share one .mode-select__row so the retention band
       stops spending a second line on the old "Select mode | Custom" head.
       Outside Rail-960, §6.4 of #s9-rail rebuilds the control's two-row
       head from this markup (gated fallback — see §11.11 / §3.14.4 #5).
       ══════════════════════════════════════════════════════════════ */
    .mode-select__row {
      display: flex;
      align-items: stretch;
      gap: 8px;
      min-width: 0;
    }

    .mode-select__row .mode-grid {
      flex: 1 1 auto;
      min-width: 0;
    }

    .mode-select__row .custom-match {
      flex: 0 0 auto;
      align-self: center;
    }

    .custom-match {
      position: relative;
      isolation: isolate;
      z-index: 2;
      display: inline-flex;
      flex: 0 0 auto;
      align-items: center;
      gap: 6px;
      min-height: 22px;
      margin: 0;
      padding: 0 9px;
      border: 0;
      outline: 0;
      background: transparent;
      color: #9aa5b0;
      cursor: pointer;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 9.5px;
      font-weight: 800;
      letter-spacing: 0.12em;
      line-height: 1;
      text-transform: uppercase;
      white-space: nowrap;
      transition: color 150ms ease;
    }

    .custom-match::before {
      position: absolute;
      z-index: -1;
      inset: 0;
      clip-path: polygon(6px 0, 100% 0, calc(100% - 6px) 100%, 0 100%);
      background: rgba(255, 255, 255, 0.03);
      box-shadow: inset 0 0 0 1px rgba(168, 185, 201, 0.11);
      content: "";
      transition: background 150ms ease, box-shadow 150ms ease;
    }

    .custom-match:hover {
      color: #eef2f5;
    }

    .custom-match:hover::before {
      background: rgba(255, 255, 255, 0.06);
      box-shadow: inset 0 0 0 1px rgba(var(--amber-rgb), 0.3);
    }

    .custom-match:hover .custom-match__chev {
      opacity: 1;
      transform: translateX(2px);
    }

    .custom-match:focus-visible {
      outline: 0;
    }

    .custom-match:focus-visible::before {
      box-shadow:
        inset 0 0 0 1px rgba(var(--amber-rgb), 0.55),
        0 0 0 2px rgba(var(--amber-rgb), 0.5);
    }

    .custom-match__mark {
      display: grid;
      flex: 0 0 auto;
      place-items: center;
      width: 10px;
      height: 10px;
      color: rgba(var(--amber-rgb), 0.78);
      font-size: 9px;
      line-height: 1;
      transition: color 150ms ease;
    }

    .custom-match:hover .custom-match__mark {
      color: var(--amber-hot, #ffc252);
    }

    .custom-match__chev {
      display: block;
      width: 8px;
      height: 8px;
      opacity: 0.5;
      transition: transform 150ms var(--ease-out), opacity 150ms ease;
    }

    .custom-match__chev svg {
      display: block;
      width: 100%;
      height: 100%;
      fill: none;
      stroke: currentColor;
      stroke-width: 2;
      stroke-linecap: square;
      stroke-linejoin: miter;
    }

    /* Custom path open (hub or lobby) — squad-tab selected DNA, not a slab.
       Rail chrome only on Play. */
    body[data-play-path="custom"][data-lobby-panel="play"] .custom-match {
      color: #fff;
    }

    body[data-play-path="custom"][data-lobby-panel="play"] .custom-match::before {
      background: linear-gradient(180deg, rgba(var(--amber-rgb), 0.16), rgba(var(--amber-rgb), 0.04));
      box-shadow:
        inset 0 -2px 0 var(--amber),
        inset 0 0 0 1px rgba(var(--amber-rgb), 0.28);
    }

    body[data-play-path="custom"][data-lobby-panel="play"] .custom-match .custom-match__mark {
      color: var(--amber-hot, #ffc252);
    }

    body[data-play-path="custom"][data-lobby-panel="play"] .custom-match .custom-match__chev {
      width: 0;
      opacity: 0;
      transform: none;
    }

    /* The quick-play mode radios stay dim for the whole custom path — you are
       not picking a quick match from in here. The slab stays hot: hub and
       live lobby both offer Back to Quick Play (full exit). */
    body[data-play-path="custom"][data-lobby-panel="play"] .mode-grid {
      opacity: 0.38;
      pointer-events: none;
      filter: grayscale(0.2);
      transition: opacity 280ms var(--ease-out), filter 280ms var(--ease-out);
    }

    /* ── The slab as a way back ─────────────────────────────────────────
       Quick Play is mounted on every screen, which is right until the player
       is somewhere the promise "start a new match" is wrong. There are two
       such places, and one treatment answers both — amber gives way to cold
       steel, the arrow turns around, and the subtitle says where you land:

         on Play, path open    BACK TO QUICK PLAY  steel. Leaves any live
                                                   lobby and closes Custom.
         off Play, path open   BACK TO CUSTOM      steel. Goes back into the
                                                   flow, hub or lobby alike.

       The trigger is the PATH being open, not a lobby existing: a player who
       opened Custom and wandered to the Store is still in that flow, and a
       hot Quick Play slab there is an invitation to lose it.

       Lobby Leave still drops you to the Custom hub; the slab is the full
       exit. It keeps the full footprint — still the biggest thing you can
       press, it just no longer promises a new match. ── */
    .qp-return { display: none; }

    body[data-cm-return] .quick-play__copy,
    body[data-cm-return] .quick-play__progress { display: none; }

    body[data-cm-return] .qp-return {
      position: relative;
      z-index: 1;
      display: block;
      min-width: 0;
    }

    /* Cold steel for both return states — amber stays the launch CTA.
       Same slab geometry (clip, sheen, drop shadow); only the plate, its
       underplate, the top hairline, and the title shadow cool off. */
    body[data-cm-return] .quick-play {
      background:
        linear-gradient(90deg, transparent 70%, rgba(0, 0, 0, 0.16) 100%),
        linear-gradient(180deg, #5a6570 0%, #3d4752 52%, #2c343d 100%);
    }

    body[data-cm-return] .quick-play-frame::before {
      background: #1f262e;
    }

    body[data-cm-return] .quick-play::before {
      background: linear-gradient(
          90deg,
          rgba(255, 255, 255, 0.42),
          rgba(200, 210, 220, 0.16) 52%,
          transparent 88%
        )
        top / 100% 1px no-repeat;
    }

    body[data-cm-return] .quick-play__arrow { transform: scaleX(-1); }

    body[data-cm-return] .quick-play:hover .quick-play__arrow {
      transform: scaleX(-1) translateX(2px);
    }

    /* Fitted, not fixed: Quick Play gets 34px for 10 characters, "Back to
       Custom" is 14 and "Back to Quick Play" 18, so each drops to whatever
       clears the arrow on one line. */
    body[data-cm-return="quick"] .qp-return__title {
      font-size: 20px;
      letter-spacing: 0.03em;
    }
    /* Same type recipe as .quick-play__title / __subtitle; cool shadow so
       the plate does not keep a warm amber cast. */
    .qp-return__title {
      display: block;
      overflow: hidden;
      font-family: Rajdhani, "Arial Narrow", sans-serif;
      font-size: 25px;
      font-weight: 700;
      letter-spacing: 0.055em;
      line-height: 0.9;
      text-overflow: ellipsis;
      text-transform: uppercase;
      white-space: nowrap;
      text-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
    }

    .qp-return__sub {
      display: block;
      margin-top: 8px;
      overflow: hidden;
      color: rgba(255, 255, 255, 0.94);
      font-family: Rajdhani, sans-serif;
      font-size: 12px;
      font-weight: 700;
      letter-spacing: 0.09em;
      line-height: 1;
      text-overflow: ellipsis;
      text-transform: uppercase;
      white-space: nowrap;
    }

    .custom-match-panel {
      container: cm-rail / inline-size;
      position: absolute;
      inset: 0;
      z-index: 4;
      display: flex;
      flex-direction: column;
      min-height: 0;
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
      transform: translate3d(12px, 0, 0);
      transition:
        opacity 260ms var(--ease-out),
        transform 320ms var(--ease-out),
        visibility 0s linear 260ms;
    }

    /* Session persists off-Play. Play + Killstreaks keep the Custom rail —
       Killstreaks owns the center aperture only. Store / Inventory /
       Leaderboards consume the RHS, so the rail yields there. */
    body[data-play-path="custom"]:is([data-lobby-panel="play"], [data-lobby-panel="loadout"]) .play-right-stack {
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
      transform: translate3d(-8px, 0, 0);
      transition:
        opacity 240ms var(--ease-out),
        transform 300ms var(--ease-out),
        visibility 0s linear 240ms;
    }

    body[data-play-path="custom"]:is([data-lobby-panel="play"], [data-lobby-panel="loadout"]) .custom-match-panel {
      opacity: 1;
      visibility: visible;
      pointer-events: auto;
      transform: none;
      transition:
        opacity 260ms var(--ease-out),
        transform 320ms var(--ease-out),
        visibility 0s;
    }

    /* ══════════════════════════════════════════════════════════════
       PLAY TAB = lobby session cue + return control
       No dropdown, no push bar. Two problems the first pass had:

       1. REFLOW. The tab only widened while away from Play, so every
          Play → Store → Play trip shoved Killstreaks sideways. The tab now
          reserves the WIDEST state's width (--cm-nav-w) the moment a lobby
          exists, in EVERY mode. Only creating/leaving a lobby changes the
          footprint, and that one change transitions.

       2. TRUNCATION. The old single line uppercased "{host}'s Lobby" and
          ellipsised it, so a long display name ate the word that told you
          what the tab was. Split it: the host name is the only truncatable
          run (line 1, natural case = data), and "LOBBY" sits under it as
          fixed chrome. Clipped or not, it still reads as a lobby name.
       ══════════════════════════════════════════════════════════════ */
    .slant-nav__item[data-nav="play"] {
      transition:
        min-width 220ms var(--ease-spring),
        color 150ms ease;
    }

    body[data-cm-phase="lobby"] .slant-nav__item[data-nav="play"] {
      min-width: var(--cm-nav-w, 154px);
    }

    .slant-nav__item[data-nav="play"] .slant-nav__label-stack {
      display: none;
      flex-direction: column;
      align-items: flex-start;
      justify-content: center;
      gap: 4px;
      min-width: 0;
      max-width: 100%;
      text-align: left;
    }

    .slant-nav__item[data-nav="play"] .slant-nav__label-main {
      display: inline-flex;
      align-items: center;
    }

    /* On Play: the session reads as a badge on the tab, same chip language
       as .squad-tab__badge / .slant-nav__badge. */
    .slant-nav__item[data-nav="play"] .slant-nav__lobby-chip {
      display: none;
      align-items: center;
      min-height: 15px;
      margin-left: 7px;
      padding: 0 5px;
      border: 0;
      border-radius: 3px;
      background: rgba(var(--amber-rgb), 0.14);
      box-shadow: inset 0 0 0 1px rgba(var(--amber-rgb), 0.3);
      color: var(--amber-hot, #ffc252);
      font-family: Inter, system-ui, sans-serif;
      font-size: 8px;
      font-weight: 700;
      letter-spacing: 0.09em;
      line-height: 1;
      text-transform: uppercase;
    }

    /* Line 1 — the only run allowed to clip. Natural case: this is the
       host's display name, not nav chrome. */
    .slant-nav__lobby-name {
      display: block;
      max-width: 100%;
      overflow: hidden;
      color: #f4e8d6;
      font-family: Rajdhani, "Bahnschrift SemiCondensed", "Arial Narrow", sans-serif;
      font-size: 13px;
      font-weight: 700;
      letter-spacing: 0.02em;
      line-height: 1;
      text-overflow: ellipsis;
      text-transform: none;
      white-space: nowrap;
    }

    /* Line 2 — fixed chrome. Never truncates, so the tab always names itself. */
    .slant-nav__lobby-line {
      display: block;
      color: rgba(var(--amber-rgb), 0.86);
      font-family: Inter, system-ui, sans-serif;
      font-size: 8px;
      font-weight: 700;
      letter-spacing: 0.19em;
      line-height: 1;
      text-transform: uppercase;
    }

    /* On Play while lobbied: quiet chip only */
    body[data-cm-phase="lobby"][data-lobby-panel="play"] .slant-nav__item[data-nav="play"] .slant-nav__lobby-chip {
      display: inline-flex;
    }

    /* Away from Play while lobbied: Play becomes return-to-lobby.
       Left padding clears the key plate's 9px..27px footprint with a 6px
       optical gap — the old 20px gutter ran the label straight into it. */
    body[data-cm-phase="lobby"]:not([data-lobby-panel="play"]) .slant-nav__item[data-nav="play"] {
      padding: 0 13px 0 33px;
      color: #f2e6d2;
    }

    /* width:100% bounds the stack to the tab's content box (154 − 46 = 108px),
       which is what gives .slant-nav__lobby-name something to ellipsis against.
       Without it the label sizes to its text and a long name overflows the tab. */
    body[data-cm-phase="lobby"]:not([data-lobby-panel="play"]) .slant-nav__item[data-nav="play"] .slant-nav__label {
      display: flex;
      justify-content: flex-start;
      width: 100%;
      min-width: 0;
      max-width: 100%;
      transform: none;
    }

    /* Plate grows to span both lines so it reads as a key, not a bullet. */
    body[data-cm-phase="lobby"]:not([data-lobby-panel="play"]) .slant-nav__item[data-nav="play"] .slant-nav__return {
      left: 9px;
      width: 18px;
      height: 27px;
      opacity: 1;
      transform: translateY(-50%);
    }

    body[data-cm-phase="lobby"]:not([data-lobby-panel="play"]) .slant-nav__item[data-nav="play"]:hover .slant-nav__return {
      transform: translateY(-50%) translateX(-2px);
    }

    body[data-cm-phase="lobby"]:not([data-lobby-panel="play"]) .slant-nav__item[data-nav="play"] .slant-nav__label-main,
    body[data-cm-phase="lobby"]:not([data-lobby-panel="play"]) .slant-nav__item[data-nav="play"] .slant-nav__lobby-chip {
      display: none;
    }

    body[data-cm-phase="lobby"]:not([data-lobby-panel="play"]) .slant-nav__item[data-nav="play"] .slant-nav__label-stack {
      display: flex;
    }

    body[data-cm-phase="lobby"]:not([data-lobby-panel="play"]) .slant-nav__item[data-nav="play"] .slant-nav__surface::before {
      background: linear-gradient(180deg, rgba(var(--amber-rgb), 0.26), rgba(255, 255, 255, 0.06) 52%, rgba(var(--amber-rgb), 0.16));
    }

    /* Narrow shells already tighten every tab; keep the reservation in step
       so the nav still never reflows on a mode change. */
    @media (max-width: 1180px) {
      body[data-cm-phase="lobby"] .slant-nav__item[data-nav="play"] {
        min-width: 138px;
      }
    }

    /* ══════════════════════════════════════════════════════════════
       CUSTOM MATCH PANEL — right-rail session surface

       CONTROL VOCABULARY. The first pass gave mode, bot difficulty, bot
       team and list filters the same chamfered pill, so nothing read as
       more important than anything else. The chamfer now means exactly one
       thing — "this is a button you press to commit" — and everything else
       earns its weight from size and space instead of chrome:

         chamfered slab   48px, amber   Start Match / Create Lobby (one per view)
         chamfered button 34px, steel   Join / Invite / Leave / Copy
         chamfered button 28px, steel   Add bot — the smallest commit there is
         chamfered tab    32px          Join | Create

       MATCH SETUP LADDER. The second pass gave Mode, Max and Bots the same
       34px label-left/control-right row, so all three read as one tier and
       the player had to read words to find the decision that matters. They
       are now three different sizes of thing, in Create and in the live
       lobby alike:

         1 mode        62px, bare    24px glyph + 11px name, amber underline,
                                     and the selected tile lights from the
                                     top. The only full white in the group.
                                     The lobby's OWN .mode-card language,
                                     borrowed by look and not by class —
                                     quick-play.js owns every .mode-card as
                                     a radio, so these are .cm-mode.
         - brief       13.5px        what the selected mode actually is, in
                                     Rajdhani behind a single amber accent
                                     bar. The game's voice, not chrome — and
                                     the only prose in the panel set at a
                                     size you read rather than scan.
         2 max         46px, bare    the same 3-up .cm-mode grid minus the
                                     glyph, 23px Saira numerals. Same shape
                                     as Mode because it is the same kind of
                                     decision; 16px shorter because it is
                                     the smaller one.
         3 bots        24px seg      under a hairline, 8.5px micro-label with
                                     the roster's robot glyph, never pure
                                     white, resting at 0.82 opacity. Tooling
                                     that acts on a match tiers 1-2 defined.

       Everything else is inherited: .lb-panel shell/header, .squad-tab tabs,
       .squad-member rows, .member-kick, .request-row list rows.
       ══════════════════════════════════════════════════════════════ */
    @keyframes cm-signal {
      0%, 100% { opacity: 0.48; transform: scale(0.82); }
      50% { opacity: 1; transform: scale(1); }
    }

    .cm-panel {
      position: relative;
      isolation: isolate;
      display: flex;
      flex-direction: column;
      gap: 13px;
      height: 100%;
      min-height: 0;
      padding: 0 12px 13px;
      overflow: hidden;
      border: 1px solid rgba(171, 188, 204, 0.16);
      clip-path: polygon(0 0, calc(100% - 11px) 0, 100% 11px, 100% 100%, 11px 100%, 0 calc(100% - 11px));
      background:
        linear-gradient(150deg, rgba(var(--amber-rgb), 0.055), transparent 30%),
        linear-gradient(180deg, #0b1117, #06090d);
      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.025);
    }

    /* The chamfered clip already says "panel corner"; the 2px L-brackets that
       used to sit in them were a second corner drawn on top of the first. */

    /* ── Header — Killstreaks' honeycomb, in steel ─────────────────────
       Same primitives as .loadout__header (loadout.css owns .hex-field /
       .hex-field__layer / .hex-field__glow / .hex-cell): one seamless
       flat-top hex tile, a second copy of that tile masked to a single hot
       spot, and a handful of filled cells. Reused rather than re-drawn, so
       the two headers stay one system — the only differences are that the
       geometry vars live here and every amber in the recipe becomes steel,
       which is what tells a Custom Match apart from Killstreaks at a
       glance. The old skewed-chevron band was neither. ── */
    .cm-panel__header {
      /* .hex-field* read these off their ancestor; .loadout declares them for
         the Killstreaks header, so the Custom rail declares its own. A tighter
         cell than the 35px there, because this header is shorter. */
      --hex-w: 34px;
      --hex-line-alpha: 0.24;
      --hex-start: 0%;
      --hex-floor: 1;
      --hex-glow: 0.5;
      --scrim: 0.72;

      position: relative;
      isolation: isolate;
      display: flex;
      flex: 0 0 auto;
      align-items: center;
      justify-content: space-between;
      gap: 10px;
      margin: 0 -12px;
      padding: 13px 12px 12px 15px;
      overflow: hidden;
      background: linear-gradient(90deg, rgba(6, 9, 13, 0.99) 0 30%, rgba(7, 11, 15, 0.9) 56%, rgba(11, 16, 22, 0.82));
    }

    /* Scrim over the field, under the type: the title has to stay legible
       where the honeycomb is densest. */
    .cm-panel__header::before {
      position: absolute;
      z-index: 1;
      inset: 0;
      background:
        radial-gradient(
          168px 58px at 62px 50%,
          rgba(5, 8, 12, calc(0.95 * var(--scrim))),
          rgba(5, 8, 12, calc(0.66 * var(--scrim))) 44%,
          rgba(5, 8, 12, 0) 76%
        ),
        linear-gradient(
          90deg,
          rgba(5, 8, 12, calc(0.68 * var(--scrim))) 0,
          rgba(5, 8, 12, calc(0.3 * var(--scrim))) 40%,
          rgba(5, 8, 12, 0) 68%
        );
      content: "";
      pointer-events: none;
    }

    .cm-panel__header::after {
      position: absolute;
      right: 0;
      bottom: 0;
      left: 0;
      z-index: 4;
      height: 1px;
      background: linear-gradient(90deg, rgba(171, 188, 204, 0.2), rgba(171, 188, 204, 0.08) 56%, transparent);
      content: "";
      pointer-events: none;
    }

    /* Steel recolour of the shared recipe — stroke and cell fill only, so the
       tile geometry stays byte-identical to the Killstreaks one. */
    .cm-panel__header .hex-cell {
      background: rgba(171, 188, 204, var(--fill, 0.07));
    }

    .cm-panel__header .hex-field__glow {
      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 17.32'%3E%3Cg fill='none' stroke='%23cfdcea' stroke-width='.5' stroke-linejoin='round'%3E%3Cpath d='M10 0L5 8.66L-5 8.66L-10 0L-5 -8.66L5 -8.66Z'/%3E%3Cpath d='M10 17.32L5 25.98L-5 25.98L-10 17.32L-5 8.66L5 8.66Z'/%3E%3Cpath d='M40 0L35 8.66L25 8.66L20 0L25 -8.66L35 -8.66Z'/%3E%3Cpath d='M40 17.32L35 25.98L25 25.98L20 17.32L25 8.66L35 8.66Z'/%3E%3Cpath d='M25 8.66L20 17.32L10 17.32L5 8.66L10 0L20 0Z'/%3E%3C/g%3E%3C/svg%3E");
    }

    .cm-heading {
      position: relative;
      z-index: 2;
      min-width: 0;
    }

    .cm-panel__kicker {
      display: flex;
      align-items: center;
      gap: 6px;
      margin: 0 0 7px;
      color: var(--amber-hot, #ffc252);
      font: 700 8px/1 "Saira Condensed", Rajdhani, sans-serif;
      letter-spacing: 0.23em;
      text-transform: uppercase;
    }

    .cm-panel__fill {
      color: #7d8892;
      font-variant-numeric: tabular-nums;
      letter-spacing: 0.1em;
    }

    .cm-panel__fill::before {
      margin-right: 6px;
      color: rgba(171, 188, 204, 0.3);
      content: "\00b7";
    }

    .cm-panel__fill[hidden] {
      display: none;
    }

    /* Full is a state, so it rides the count it qualifies rather than
       spending a line of rail on a sentence. */
    .cm-panel__max {
      display: inline-block;
      margin-left: 6px;
      padding: 2px 4px 1px;
      border-radius: 2px;
      background: rgba(var(--amber-rgb), 0.16);
      color: var(--amber-hot, #ffc252);
      font-size: 7.5px;
      font-weight: 800;
      letter-spacing: 0.16em;
      vertical-align: 1px;
    }

    .cm-panel__title {
      margin: 0;
      overflow: hidden;
      color: #fff;
      font: 700 22px/0.92 "Saira Condensed", Rajdhani, sans-serif;
      letter-spacing: 0.04em;
      text-overflow: ellipsis;
      text-transform: uppercase;
      white-space: nowrap;
      text-shadow: 0 1px 2px rgba(0, 0, 0, 0.92), 0 2px 16px rgba(0, 0, 0, 0.78);
    }

    .cm-headtools {
      position: relative;
      z-index: 3;
      display: flex;
      flex: 0 0 auto;
      align-items: center;
      gap: 6px;
    }

    .cm-exit {
      display: inline-flex;
      flex: 0 0 auto;
      min-width: 30px;
      min-height: 30px;
      align-items: center;
      justify-content: center;
      margin: 0;
      padding: 0 10px;
      border: 1px solid rgba(171, 188, 204, 0.15);
      outline: 0;
      clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
      background: rgba(7, 11, 15, 0.72);
      color: #8f9aa5;
      cursor: pointer;
      font: 700 9px/1 "Saira Condensed", Rajdhani, sans-serif;
      letter-spacing: 0.13em;
      text-transform: uppercase;
      transition: color 150ms ease, border-color 150ms ease, background 150ms ease;
    }

    .cm-icon-btn {
      display: grid;
      flex: 0 0 auto;
      width: 30px;
      height: 30px;
      place-items: center;
      margin: 0;
      padding: 0;
      border: 1px solid rgba(171, 188, 204, 0.15);
      outline: 0;
      clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
      background: rgba(7, 11, 15, 0.72);
      color: #8f9aa5;
      cursor: pointer;
      font-size: 11px;
      transition: color 150ms ease, border-color 150ms ease, background 150ms ease;
    }

    .cm-exit:hover,
    .cm-icon-btn:hover {
      border-color: rgba(var(--amber-rgb), 0.42);
      background: rgba(var(--amber-rgb), 0.08);
      color: #f4d49a;
    }

    .cm-exit:focus-visible,
    .cm-icon-btn:focus-visible {
      outline: 2px solid var(--amber);
      outline-offset: 2px;
    }

    .cm-icon-btn[aria-busy="true"] i {
      animation: fa-spin 0.7s infinite linear;
    }

    /* Refresh belongs to the browse list, so it only exists in the hub. */
    .cm-panel[data-cm-view="lobby"] .cm-icon-btn {
      display: none;
    }

    /* ── Views ── */
    .cm-hub,
    .cm-lobby {
      display: none;
      flex: 1 1 auto;
      flex-direction: column;
      gap: 14px;
      min-height: 0;
    }

    /* The last 9px that get a full 12 onto the screen. The hub keeps 14. */
    .cm-lobby { gap: 11px; }

    .cm-panel[data-cm-view="hub"] .cm-hub,
    .cm-panel[data-cm-view="lobby"] .cm-lobby {
      display: flex;
    }

    .cm-hub {
      overflow-x: hidden;
      overflow-y: auto;
      padding-right: 2px;
      overscroll-behavior: contain;
      scrollbar-width: thin;
      scrollbar-color: rgba(var(--amber-rgb), 0.28) transparent;
    }

    .cm-hub::-webkit-scrollbar { width: 3px; }
    .cm-hub::-webkit-scrollbar-track { background: transparent; }
    .cm-hub::-webkit-scrollbar-thumb { background: rgba(var(--amber-rgb), 0.28); }

    .cm-pane {
      display: none;
      flex: 1 1 auto;
      flex-direction: column;
      gap: 14px;
      min-height: 0;
    }

    .cm-pane.is-active {
      display: flex;
    }

    /* ── Tabs (.squad-tab DNA) ──
       Pinned to the ceiling for the same reason Join-with-code is pinned to
       the floor: the feed is the only thing that should move. The negative
       margin keeps the 14px hub gap while the opaque band still reaches far
       enough down to swallow a row sliding under it. */
    .cm-tabs {
      position: sticky;
      z-index: 4;
      top: 0;
      display: grid;
      flex: 0 0 auto;
      grid-template-columns: 1fr 1fr;
      gap: 5px;
      width: 100%;
      min-width: 0;
      margin-bottom: -8px;
      padding-bottom: 8px;
      /* Sampled off .cm-panel's own gradient at this height — a flat #06090d
         here reads as a darker plate sitting on the panel. */
      background: #0a1016;
    }

    .cm-tab {
      position: relative;
      isolation: isolate;
      display: flex;
      min-width: 0;
      min-height: 32px;
      align-items: center;
      justify-content: center;
      gap: 7px;
      margin: 0;
      padding: 0 10px;
      overflow: hidden;
      border: 0;
      outline: 0;
      background: transparent;
      color: #78838e;
      cursor: pointer;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 12px;
      font-weight: 800;
      letter-spacing: 0.11em;
      text-transform: uppercase;
      transition: color 150ms ease;
    }

    .cm-tab::before {
      position: absolute;
      z-index: -1;
      inset: 0;
      clip-path: polygon(8px 0, 100% 0, calc(100% - 8px) 100%, 0 100%);
      background: rgba(255, 255, 255, 0.025);
      box-shadow: inset 0 0 0 1px rgba(168, 185, 201, 0.06);
      content: "";
      transition: background 150ms ease, box-shadow 150ms ease;
    }

    .cm-tab:hover { color: #dfe5e9; }
    .cm-tab:hover::before { background: rgba(255, 255, 255, 0.045); }
    .cm-tab[aria-selected="true"] { color: #fff; }

    .cm-tab[aria-selected="true"]::before {
      background: linear-gradient(180deg, rgba(var(--amber-rgb), 0.14), rgba(var(--amber-rgb), 0.035));
      box-shadow:
        inset 0 -2px 0 var(--amber),
        inset 0 0 0 1px rgba(var(--amber-rgb), 0.2),
        0 0 16px rgba(var(--amber-rgb), 0.06);
    }

    .cm-tab:focus-visible {
      outline: 2px solid var(--amber-hot, #ffc252);
      outline-offset: -4px;
    }

    .cm-tab__badge {
      display: inline-flex;
      min-width: 20px;
      height: 16px;
      align-items: center;
      justify-content: center;
      padding: 0 4px;
      border-radius: 3px;
      background: rgba(var(--amber-rgb), 0.13);
      color: var(--amber-hot, #ffc252);
      font-family: Inter, system-ui, sans-serif;
      font-size: 8.5px;
      font-weight: 700;
      letter-spacing: 0.04em;
    }

    .cm-tab__badge[hidden] { display: none; }

    /* ── Type scale ── */
    .cm-section {
      margin: 0 0 9px;
      color: #6f7a85;
      font: 800 9px/1 Rajdhani, Inter, sans-serif;
      letter-spacing: 0.18em;
      text-transform: uppercase;
    }

    /* ── Buttons (the only chamfered things) ── */
    .cm-btn {
      position: relative;
      display: inline-flex;
      min-height: 34px;
      align-items: center;
      justify-content: center;
      gap: 7px;
      margin: 0;
      padding: 0 14px;
      border: 0;
      outline: 0;
      clip-path: polygon(6px 0, 100% 0, calc(100% - 6px) 100%, 0 100%);
      background: linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.02));
      box-shadow: inset 0 0 0 1px rgba(171, 188, 204, 0.18);
      color: #c8d0d8;
      cursor: pointer;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 11.5px;
      font-weight: 800;
      letter-spacing: 0.09em;
      line-height: 1;
      text-transform: uppercase;
      white-space: nowrap;
      transition: background 150ms ease, box-shadow 150ms ease, color 150ms ease;
    }

    .cm-btn:hover:not(:disabled) {
      background: linear-gradient(180deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.035));
      box-shadow: inset 0 0 0 1px rgba(171, 188, 204, 0.4);
      color: #fff;
    }

    .cm-btn:focus-visible {
      outline: 2px solid var(--amber-hot, #ffc252);
      outline-offset: -2px;
    }

    .cm-btn:disabled {
      cursor: default;
      background: rgba(157, 176, 194, 0.035);
      box-shadow: inset 0 0 0 1px rgba(157, 176, 194, 0.1);
      color: #6f7a85;
    }

    .cm-btn--block { width: 100%; }

    /* Still a chamfer — it commits an action — but the smallest one, because
       adding a bot is instrumentation, not a decision about the match. */
    .cm-btn--tool {
      min-height: 28px;
      padding: 0 11px;
      font-size: 10px;
      letter-spacing: 0.07em;
    }

    /* Amber = commit. Exactly one of these is on screen at a time. */
    .cm-btn--go {
      background: linear-gradient(180deg, var(--amber-hot, #ffc252), var(--amber-deep, #d87800));
      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.34);
      color: #171006;
    }

    .cm-btn--go:hover:not(:disabled) {
      background: linear-gradient(180deg, #ffdc86, var(--amber, #ff9d0a));
      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5);
      color: #171006;
    }

    /* Amber ghost — .slot-invite affordance for accepting into something. */
    .cm-btn--accept {
      background: rgba(var(--amber-rgb), 0.07);
      box-shadow: inset 0 0 0 1px rgba(var(--amber-rgb), 0.25);
      color: var(--amber-hot, #ffc252);
    }

    .cm-btn--accept:hover:not(:disabled) {
      background: linear-gradient(180deg, var(--amber-hot, #ffc252), var(--amber-deep, #d87800));
      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.34);
      color: #171006;
    }

    .cm-btn--danger {
      background: rgba(255, 88, 62, 0.065);
      box-shadow: inset 0 0 0 1px rgba(255, 88, 62, 0.24);
      color: #ff8975;
    }

    .cm-btn--danger:hover:not(:disabled) {
      background: rgba(255, 88, 62, 0.16);
      box-shadow: inset 0 0 0 1px rgba(255, 88, 62, 0.5);
      color: #ffb0a3;
    }

    /* ── TIER 1 · Mode — the headline of a match ───────────────────────
       Borrowed by look, never by class: quick-play.js binds every .mode-card
       as a radio in its own group. Bare (no enclosure) so it reads as a
       choice of match, not a row of buttons — it leads on height, on the
       largest glyph and type in the panel, on the only full white, and on
       the hint line below that no other control gets to have. The selected
       tile lights from the top instead of gaining a border: still one
       surface, no nested frame. */
    .cm-modes {
      display: grid;
      grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: 4px;
      height: 62px;
    }

    .cm-mode {
      position: relative;
      display: flex;
      min-width: 0;
      height: 62px;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 8px;
      margin: 0;
      padding: 4px 3px 7px;
      border: 0;
      outline: 0;
      background: transparent;
      color: #616b76;
      cursor: pointer;
      transition: color 150ms ease, background 180ms ease;
    }

    .cm-mode::after {
      position: absolute;
      right: 18%;
      bottom: 0;
      left: 18%;
      height: 2px;
      background: var(--amber);
      content: "";
      opacity: 0;
      transform: scaleX(0.4);
      transition: opacity 150ms ease, transform 180ms var(--ease-out);
    }

    /* Radial, not linear: the light has to die before it reaches the tile's
       edges, or the selected mode reads as a plate inside the panel. */
    .cm-mode:hover {
      background: radial-gradient(120% 96% at 50% 0%, rgba(255, 255, 255, 0.06), transparent 74%);
      color: #cbd1d6;
    }

    .cm-mode:focus-visible {
      outline: 2px solid rgba(var(--amber-rgb), 0.75);
      outline-offset: -2px;
    }

    /* Steel lift, not an amber wash: amber over the dark face goes burnt
       orange, and it is spend-language besides. Selection is carried by the
       accents that were always doing it — the underline and the lit glyph —
       plus the only pure white in the group. */
    .cm-mode[aria-pressed="true"] {
      background: radial-gradient(122% 100% at 50% 0%, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.02) 52%, transparent 80%);
      color: #fff;
    }

    .cm-mode[aria-pressed="true"]::after {
      opacity: 1;
      transform: scaleX(1);
    }

    .cm-mode[aria-pressed="true"] .cm-mode__icon {
      color: var(--amber-hot, #ffc252);
      filter: drop-shadow(0 0 7px rgba(var(--amber-rgb), 0.4));
    }

    .cm-mode__icon {
      display: grid;
      width: 24px;
      height: 24px;
      place-items: center;
      color: currentColor;
      transition: color 150ms ease, filter 180ms ease;
    }

    .cm-mode__icon svg {
      display: block;
      width: 24px;
      height: 24px;
      fill: none;
      stroke: currentColor;
      stroke-width: 1.7;
      stroke-linecap: square;
      stroke-linejoin: miter;
    }

    .cm-mode__name {
      display: block;
      max-width: 100%;
      overflow: hidden;
      font-family: Rajdhani, sans-serif;
      font-size: 11px;
      font-weight: 800;
      letter-spacing: 0.07em;
      line-height: 1;
      text-overflow: ellipsis;
      text-transform: uppercase;
      white-space: nowrap;
    }

    /* ── Mode brief — the selected mode says what it is ────────────────
       Rajdhani, not Inter: this is the game's voice describing the game,
       not UI chrome, and at 13.5px it is the only sentence in the panel
       big enough to actually read rather than scan. One leading accent bar
       carries the hierarchy — no box, no second hairline. */
    .cm-brief {
      position: relative;
      margin: 10px 0 13px;
      padding: 1px 0 1px 12px;
      color: #a7b2bd;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 13.5px;
      font-weight: 600;
      letter-spacing: 0.012em;
      line-height: 1.42;
    }

    .cm-brief::before {
      position: absolute;
      top: 2px;
      bottom: 2px;
      left: 0;
      width: 2px;
      background: linear-gradient(180deg, var(--amber-hot, #ffc252), rgba(var(--amber-rgb), 0.14));
      content: "";
    }

    /* ── TIER 2 · Max — the mode selector's shape, one step down ───────
       Same bare 3-up grid, same underline, same steel lift; it loses the
       glyph and 16px of height, and the numeral does the talking. Reusing
       .cm-mode outright is the point: they are the same kind of decision,
       so they must be the same kind of control. */
    .cm-modes--caps { height: 46px; }

    .cm-mode--cap {
      height: 46px;
      gap: 0;
      padding: 2px 3px 7px;
    }

    .cm-mode__num {
      font-family: "Saira Condensed", Rajdhani, sans-serif;
      font-size: 23px;
      font-weight: 700;
      font-variant-numeric: tabular-nums;
      letter-spacing: 0.02em;
      line-height: 1;
    }

    /* Below the current headcount you cannot go, so it stops being a choice. */
    .cm-mode--cap:disabled {
      background: none;
      color: #3d444d;
      cursor: default;
    }

    .cm-mode--cap:disabled::after { display: none; }

    /* ── TIER 3 · Bots — tooling, not setup ────────────────────────────
       It acts ON a match the two tiers above have already defined, so it
       sits under a hairline, holds the smallest label in the panel, and
       rests at 0.82 until you reach for it. The one chamfered button here
       is deliberately the smallest commit in the panel. */
    .cm-tools {
      display: flex;
      align-items: center;
      gap: 9px;
      min-height: 30px;
      min-width: 0;
      margin-top: 3px;
      padding-top: 9px;
      border-top: 1px solid rgba(171, 188, 204, 0.07);
      opacity: 0.82;
      transition: opacity 150ms ease;
    }

    /* Label and difficulty stay a cluster — they are one instrument — and the
       button is what gets pushed to the far edge. */
    .cm-tools > .cm-btn { margin-left: auto; }

    .cm-tools__label {
      display: inline-flex;
      flex: 0 0 auto;
      align-items: center;
      gap: 6px;
      color: #79838d;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 8.5px;
      font-weight: 800;
      letter-spacing: 0.17em;
      text-transform: uppercase;
    }

    .cm-tools__label i {
      color: #5b656e;
      font-size: 10px;
    }

    /* ── Segment — a sub-setting, so no enclosure at all. Text plus the
       same amber underline the mode selector uses, two steps quieter. ── */
    .cm-seg {
      display: inline-flex;
      flex: 0 0 auto;
      align-items: center;
      gap: 2px;
    }

    .cm-seg__opt {
      position: relative;
      height: 26px;
      margin: 0;
      padding: 0 8px;
      border: 0;
      outline: 0;
      background: transparent;
      color: #6b7681;
      cursor: pointer;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 10.5px;
      font-weight: 800;
      letter-spacing: 0.1em;
      line-height: 1;
      text-transform: uppercase;
      transition: color 150ms ease;
    }

    .cm-seg__opt::after {
      position: absolute;
      right: 8px;
      bottom: 2px;
      left: 8px;
      height: 2px;
      background: var(--amber);
      content: "";
      opacity: 0;
      transform: scaleX(0.4);
      transition: opacity 150ms ease, transform 180ms var(--ease-out);
    }

    .cm-seg__opt:hover:not(:disabled) { color: #cbd1d6; }
    .cm-seg__opt[aria-pressed="true"] { color: #fff; }

    .cm-seg__opt[aria-pressed="true"]::after {
      opacity: 1;
      transform: scaleX(1);
    }

    .cm-seg__opt:disabled { cursor: default; color: #4f5862; }
    .cm-seg__opt:disabled::after { background: #4f5862; }

    .cm-seg__opt:focus-visible {
      outline: 2px solid rgba(var(--amber-rgb), 0.75);
      outline-offset: -3px;
    }

    /* Tier 3 — one clear step under Max: smaller, and never pure white, so
       an active difficulty can't be mistaken for an active match setting. */
    .cm-seg--tool .cm-seg__opt {
      height: 24px;
      padding: 0 6px;
      font-size: 9.5px;
      letter-spacing: 0.07em;
    }

    .cm-seg--tool .cm-seg__opt[aria-pressed="true"] { color: #c6ced5; }

    .cm-seg--tool .cm-seg__opt::after {
      right: 6px;
      left: 6px;
      height: 1px;
      background: rgba(var(--amber-rgb), 0.6);
    }

    .cm-seg--tool .cm-seg__opt:disabled::after { background: #4f5862; }

    /* ── Join by code — pinned to the floor of the hub ──
       A player who was given a code should never have to scroll a list they
       don't care about to use it. The feed above is the only thing that
       moves; this rides the bottom of the scrollport and the rows pass
       under it, so the scrim has to be opaque by the time it reaches the
       hairline. */
    .cm-codeblock {
      position: sticky;
      z-index: 3;
      bottom: 0;
      flex: 0 0 auto;
      margin-top: auto;
      padding-top: 13px;
      border-top: 1px solid rgba(171, 188, 204, 0.09);
      /* Solid, not translucent: a row sliding under the label has to
         disappear, not ghost through it. Matches the panel floor. */
      background: #06090d;
    }

    /* The block itself is opaque, so the only fade is the one above it —
       it tells you the feed continues under the pin. */
    .cm-codeblock::before {
      position: absolute;
      right: 0;
      bottom: 100%;
      left: 0;
      height: 26px;
      background: linear-gradient(180deg, rgba(6, 9, 13, 0), #06090d);
      content: "";
      pointer-events: none;
    }

    .cm-code {
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto;
      gap: 6px;
    }

    .cm-code__input {
      min-width: 0;
      height: 38px;
      padding: 0 13px;
      border: 0;
      outline: 0;
      border-radius: 5px;
      background: rgba(4, 7, 11, 0.72);
      box-shadow: inset 0 0 0 1px rgba(171, 188, 204, 0.16);
      color: #edf1f4;
      font-family: Rajdhani, sans-serif;
      font-size: 16px;
      font-weight: 700;
      letter-spacing: 0.22em;
      text-transform: uppercase;
    }

    .cm-code__input::placeholder { color: #4d5761; letter-spacing: 0.16em; }
    .cm-code__input:focus { box-shadow: inset 0 0 0 1px rgba(var(--amber-rgb), 0.5); }
    .cm-code .cm-btn { min-height: 38px; }

    /* ── Hub: lobby list ───────────────────────────────────────────────
       Invite-only discovery is a cold-start trap: a player whose friends
       are offline can never reach the feature. One ranked feed — invites,
       then friends' lobbies, then open — each tier sorted by how close it
       is to STARTING, because a lobby that fills is the only kind that
       retains anyone. No filter bar and no count header: with a handful of
       lobbies they were chrome describing chrome. ── */
    .cm-browse {
      display: grid;
      flex: 0 0 auto;
      gap: 6px;
    }

    .cm-lrow {
      display: grid;
      min-height: 54px;
      grid-template-columns: 38px minmax(0, 1fr) auto;
      align-items: center;
      gap: 11px;
      padding: 7px 8px;
      border-radius: 6px;
      background: rgba(5, 8, 11, 0.7);
      box-shadow: inset 0 0 0 1px rgba(174, 191, 207, 0.075);
      transition: box-shadow 150ms ease, background 150ms ease;
    }

    @media (hover: hover) {
      .cm-lrow:hover { box-shadow: inset 0 0 0 1px rgba(174, 191, 207, 0.2); }
    }

    /* Someone asked you personally — the only row that gets amber. */
    .cm-lrow--invited {
      background:
        linear-gradient(100deg, rgba(var(--amber-rgb), 0.07), transparent 58%),
        rgba(5, 8, 11, 0.72);
      box-shadow: inset 0 0 0 1px rgba(var(--amber-rgb), 0.22);
    }

    .cm-lrow--friend { box-shadow: inset 0 0 0 1px rgba(var(--green-rgb), 0.16); }
    .cm-lrow.is-shut { opacity: 0.5; }

    /* Mode badge sits where a rank insignia would — a lobby has a mode, not
       a rank. Icon over abbreviation so it reads at a glance. */
    .cm-lrow__mode {
      display: grid;
      width: 38px;
      height: 38px;
      align-content: center;
      justify-items: center;
      gap: 3px;
      border-radius: 5px;
      background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.012));
      box-shadow: inset 0 0 0 1px rgba(174, 191, 207, 0.1);
      color: #9aa5b0;
    }

    .cm-lrow--invited .cm-lrow__mode {
      background: linear-gradient(180deg, rgba(var(--amber-rgb), 0.14), rgba(var(--amber-rgb), 0.03));
      box-shadow: inset 0 0 0 1px rgba(var(--amber-rgb), 0.24);
      color: var(--amber-hot, #ffc252);
    }

    .cm-lrow__mode svg {
      display: block;
      width: 16px;
      height: 16px;
      fill: none;
      stroke: currentColor;
      stroke-width: 1.8;
      stroke-linecap: square;
      stroke-linejoin: miter;
    }

    .cm-lrow__mode small {
      font: 800 6.5px/1 Rajdhani, Inter, sans-serif;
      letter-spacing: 0.1em;
      text-transform: uppercase;
    }

    .cm-lrow__copy {
      display: flex;
      min-width: 0;
      flex-direction: column;
      gap: 6px;
      line-height: 1;
    }

    .cm-lrow__title {
      display: flex;
      min-width: 0;
      align-items: center;
      gap: 7px;
    }

    .cm-lrow__name {
      overflow: hidden;
      color: #edf1f4;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 13px;
      font-weight: 800;
      letter-spacing: 0.03em;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .cm-lrow__flag {
      display: inline-flex;
      flex: 0 0 auto;
      height: 15px;
      align-items: center;
      padding: 0 5px;
      border-radius: 3px;
      background: rgba(var(--amber-rgb), 0.14);
      color: var(--amber-hot, #ffc252);
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 7.5px;
      font-weight: 800;
      letter-spacing: 0.1em;
      text-transform: uppercase;
    }

    .cm-lrow__flag--friend {
      background: rgba(var(--green-rgb), 0.12);
      color: var(--green);
    }

    .cm-lrow__meta {
      display: flex;
      min-width: 0;
      align-items: center;
      gap: 7px;
      overflow: hidden;
      color: #7e8994;
      font-family: Inter, system-ui, sans-serif;
      font-size: 9.5px;
      font-weight: 600;
      letter-spacing: 0.04em;
      white-space: nowrap;
    }

    .cm-lrow__sep { color: rgba(171, 188, 204, 0.28); }
    .cm-lrow__fill { color: #aab4bd; font-variant-numeric: tabular-nums; }

    /* Status is the only thing on the row that decides a click, so it is the
       only thing that gets colour. */
    .cm-lrow__state {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      overflow: hidden;
      color: #8f9aa5;
      font-weight: 700;
      letter-spacing: 0.07em;
      text-overflow: ellipsis;
      text-transform: uppercase;
    }

    .cm-lrow__state::before {
      width: 5px;
      height: 5px;
      flex: 0 0 auto;
      border-radius: 50%;
      background: currentColor;
      box-shadow: 0 0 6px currentColor;
      content: "";
    }

    .cm-lrow__state--lobby { color: var(--green); }
    .cm-lrow__state--starting { color: var(--amber-hot, #ffc252); }
    .cm-lrow__state--progress { color: #ff8975; }
    .cm-lrow__state--ending { color: #6c7681; }
    .cm-lrow__state--ending::before { box-shadow: none; }

    .cm-browse__empty {
      display: grid;
      gap: 7px;
      padding: 30px 14px;
      border-radius: 6px;
      background: rgba(0, 0, 0, 0.2);
      box-shadow: inset 0 0 0 1px rgba(174, 191, 207, 0.055);
      text-align: center;
    }

    .cm-browse__empty strong {
      color: #b7c0c9;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 12px;
      font-weight: 800;
      letter-spacing: 0.11em;
      text-transform: uppercase;
    }

    .cm-browse__empty span {
      color: #66717c;
      font-family: Inter, system-ui, sans-serif;
      font-size: 10px;
      line-height: 1.5;
    }

    /* ── Match setup — one group, three tiers, shared by Create and host ──
       Mode leads at 62px with the brief under it, Max answers in the same
       shape at 46px, Bots sits under a hairline as tooling. The only
       difference between the two views is that Create has no Bots shelf —
       same language, same sizes, so the lobby you get is the one you
       configured. */
    .cm-setup {
      display: flex;
      flex: 0 0 auto;
      flex-direction: column;
      gap: 0;
      padding-bottom: 13px;
      border-bottom: 1px solid rgba(171, 188, 204, 0.09);
      transition: opacity 180ms ease;
    }

    .cm-setup .cm-section { margin-bottom: 8px; }

    /* In the hub the pane already closes with the Create slab, so the group
       needs no hairline of its own. */
    .cm-setup--create {
      padding-bottom: 0;
      border-bottom: 0;
    }

    /* ── Live lobby density ────────────────────────────────────────────
       In the hub the setup IS the screen. Once the lobby exists the roster
       is, and twelve players have to land without a scrollbar — so the same
       controls run at roughly two-thirds height. Same shapes, same order,
       same amber underline; only the scale is context-dependent. This block
       is worth ~82px of roster. */
    .cm-setup--live { padding-bottom: 7px; }

    .cm-setup--live .cm-section { margin-bottom: 3px; }

    .cm-setup--live .cm-modes { height: 42px; }

    .cm-setup--live .cm-mode {
      height: 42px;
      gap: 4px;
      padding: 3px 3px 5px;
    }

    .cm-setup--live .cm-mode__icon,
    .cm-setup--live .cm-mode__icon svg {
      width: 17px;
      height: 17px;
    }

    .cm-setup--live .cm-mode__name {
      font-size: 9.5px;
      letter-spacing: 0.05em;
    }

    .cm-setup--live .cm-brief {
      margin: 6px 0 6px;
      padding-left: 10px;
      font-size: 12px;
    }

    .cm-setup--live .cm-modes--caps { height: 26px; }

    .cm-setup--live .cm-mode--cap {
      height: 26px;
      padding: 0 3px 4px;
    }

    .cm-setup--live .cm-mode__num { font-size: 15px; }

    /* At 42px the lift's falloff is compressed into the tile and starts to
       read as a plate, so it drops to a whisper — the underline and the
       white are already carrying selection. */
    .cm-setup--live .cm-mode[aria-pressed="true"] {
      background: radial-gradient(122% 100% at 50% 0%, rgba(255, 255, 255, 0.042), transparent 74%);
    }

    .cm-setup--live .cm-tools {
      min-height: 24px;
      margin-top: 2px;
      padding-top: 6px;
    }

    .cm-setup--live .cm-seg--tool .cm-seg__opt { height: 22px; }

    .cm-setup--live .cm-btn--tool {
      min-height: 24px;
      padding: 0 9px;
      font-size: 9.5px;
    }

    /* Rounds disables bots: the shelf holds its place (no layout jump) and
       the reason surfaces under it. */
    .cm-tools:hover:not(.is-off),
    .cm-tools:focus-within:not(.is-off) { opacity: 1; }

    .cm-setup__bots.is-off { opacity: 0.5; }

    .cm-bots__summary {
      margin: 5px 0 0;
      color: #66717c;
      font-family: Inter, system-ui, sans-serif;
      font-size: 9.5px;
      line-height: 1.3;
    }

    .cm-bots__summary[hidden] { display: none; }

    /* ── Lobby: ROSTER — the hero ──────────────────────────────────────
       Two columns in both modes, so 12 players read without scrolling: TDM
       gets true side-by-side teams, FFA flows one list across both. Rows are
       one line with a single trailing cell — the role chip on rows that can
       never be kicked, the kick target on the rest — so nothing competes
       with the name at a ~150px column width.

       Open slots are passive. They were carrying their own Invite button,
       which repeated the Invite in the share strip six inches below and made
       the list look like a toolbar. ── */
    .cm-roster {
      display: flex;
      flex: 1 1 auto;
      flex-direction: column;
      min-height: 108px;
    }

    .cm-roster__list {
      flex: 1 1 auto;
      min-height: 0;
      padding-right: 2px;
      overflow-x: hidden;
      overflow-y: auto;
      overscroll-behavior: contain;
      scrollbar-width: thin;
      scrollbar-color: rgba(var(--amber-rgb), 0.28) transparent;
      contain: layout paint style;
    }

    .cm-roster__list::-webkit-scrollbar { width: 3px; }
    .cm-roster__list::-webkit-scrollbar-track { background: transparent; }
    .cm-roster__list::-webkit-scrollbar-thumb { background: rgba(var(--amber-rgb), 0.28); }

    .cm-roster__list[data-layout="tdm"] {
      display: grid;
      grid-template-columns: 1fr 1fr;
      align-items: start;
      gap: 9px;
    }

    .cm-roster__list[data-layout="ffa"] .cm-slots {
      grid-template-columns: 1fr 1fr;
      column-gap: 9px;
    }

    /* Heads stay put while the list scrolls — with 12+ rows you otherwise
       lose which column is which the moment you move. */
    .cm-team__head {
      position: sticky;
      top: 0;
      z-index: 1;
      display: flex;
      min-height: 18px;
      align-items: center;
      justify-content: space-between;
      gap: 8px;
      margin: 0 0 6px;
      padding: 0 3px 3px;
      background: linear-gradient(180deg, #0a0f15 62%, rgba(10, 15, 21, 0));
      color: #6f7a85;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 9px;
      font-weight: 800;
      letter-spacing: 0.16em;
      text-transform: uppercase;
    }

    .cm-team--allies .cm-team__head { color: #86a9c6; }
    .cm-team--enemies .cm-team__head { color: #c68f86; }

    .cm-team__count {
      color: #8f9aa5;
      font-variant-numeric: tabular-nums;
      letter-spacing: 0.08em;
    }

    .cm-slots {
      display: grid;
      grid-template-columns: 1fr;
      gap: 4px;
      align-content: start;
    }

    .cm-slot {
      position: relative;
      display: grid;
      min-height: 32px;
      grid-template-columns: 24px minmax(0, 1fr) auto;
      align-items: center;
      gap: 8px;
      padding: 3px 5px 3px 7px;
      overflow: hidden;
      border-radius: 5px;
      background:
        linear-gradient(100deg, rgba(255, 255, 255, 0.04), transparent 62%),
        rgba(5, 8, 11, 0.62);
      box-shadow: inset 0 0 0 1px rgba(174, 191, 207, 0.075);
      transition: background 150ms ease, box-shadow 150ms ease;
    }

    @media (hover: hover) {
      .cm-slot:hover { box-shadow: inset 0 0 0 1px rgba(174, 191, 207, 0.17); }
    }

    .cm-slot--host {
      background:
        linear-gradient(100deg, rgba(var(--amber-rgb), 0.085), transparent 58%),
        rgba(5, 8, 11, 0.72);
    }

    .cm-slot--you {
      background:
        linear-gradient(100deg, rgba(var(--cyan-rgb), 0.08), transparent 58%),
        rgba(5, 8, 11, 0.7);
    }

    .cm-slot--host::before,
    .cm-slot--you::before {
      position: absolute;
      top: 5px;
      bottom: 5px;
      left: 0;
      width: 2px;
      border-radius: 0 2px 2px 0;
      content: "";
    }

    .cm-slot--you::before {
      background: var(--cyan);
      box-shadow: 0 0 8px rgba(var(--cyan-rgb), 0.35);
    }

    /* Host wins the accent when you are the host. */
    .cm-slot--host::before {
      background: var(--amber);
      box-shadow: 0 0 8px rgba(var(--amber-rgb), 0.35);
    }

    .cm-slot--bot {
      background: rgba(5, 8, 11, 0.5);
      box-shadow: inset 0 0 0 1px rgba(174, 191, 207, 0.055);
    }

    .cm-slot__mark {
      display: grid;
      width: 24px;
      height: 24px;
      place-items: center;
      overflow: hidden;
      border-radius: 4px;
      background:
        radial-gradient(circle at 50% 25%, rgba(var(--amber-rgb), 0.1), transparent 62%),
        rgba(8, 12, 16, 0.84);
      box-shadow: inset 0 0 0 1px rgba(174, 191, 207, 0.08);
      color: #8f9aa5;
      font-size: 9px;
    }

    .cm-slot__mark img {
      display: block;
      width: 23px;
      height: 23px;
      object-fit: contain;
      filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.45));
    }

    .cm-slot--bot .cm-slot__mark {
      background: rgba(157, 176, 194, 0.045);
      color: #77828d;
    }

    .cm-slot__name {
      overflow: hidden;
      color: #eef2f5;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 12px;
      font-weight: 800;
      letter-spacing: 0.03em;
      line-height: 1;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .cm-slot--host .cm-slot__name { color: #ffeacb; }
    .cm-slot--you .cm-slot__name { color: #dcf0fd; }
    .cm-slot--bot .cm-slot__name { color: #aeb8c1; font-weight: 700; }

    /* Trailing cell A: role chip on rows with no kick target. */
    .cm-slot__tag {
      display: inline-flex;
      flex: 0 0 auto;
      height: 16px;
      align-items: center;
      padding: 0 5px;
      border-radius: 3px;
      background: rgba(var(--amber-rgb), 0.13);
      color: var(--amber-hot, #ffc252);
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 7.5px;
      font-weight: 800;
      letter-spacing: 0.1em;
      text-transform: uppercase;
    }

    .cm-slot__tag--you {
      background: rgba(var(--cyan-rgb), 0.15);
      color: #8fd0f7;
    }

    /* Trailing cell B: kick / remove — .member-kick language. Always
       present so touch and keyboard never depend on hover. The X is
       drawn in CSS (2px bars) so it does not depend on an 8px FA
       glyph vanishing into the slot. 26px is the budget: 24px mark +
       name + chip still fit a ~150px column without wrapping. */
    .cm-kick {
      position: relative;
      display: grid;
      width: 26px;
      min-width: 26px;
      height: 26px;
      flex: 0 0 auto;
      place-items: center;
      margin: 0;
      padding: 0;
      border: 0;
      border-radius: 4px;
      outline: 0;
      background: rgba(255, 92, 65, 0.2);
      box-shadow: inset 0 0 0 1px rgba(255, 168, 148, 0.7);
      color: #ffd4c8;
      cursor: pointer;
      line-height: 1;
      transition:
        background 140ms ease,
        box-shadow 140ms ease,
        color 140ms ease;
    }

    .cm-kick::before,
    .cm-kick::after {
      position: absolute;
      top: 50%;
      left: 50%;
      width: 11px;
      height: 2px;
      border-radius: 1px;
      background: currentColor;
      content: "";
    }

    .cm-kick::before { transform: translate(-50%, -50%) rotate(45deg); }
    .cm-kick::after { transform: translate(-50%, -50%) rotate(-45deg); }

    /* FA xmark is still in the markup (same as the forked panel) but
       the bars above are the visible mark — hide the glyph so we
       never paint two crosses. */
    .cm-kick i {
      display: none;
    }

    .cm-kick:hover,
    .cm-kick:focus-visible {
      background: rgba(255, 92, 65, 0.34);
      box-shadow: inset 0 0 0 1px rgba(255, 196, 178, 0.95);
      color: #fff1ec;
    }

    .cm-kick:focus-visible {
      outline: 2px solid #ffb09c;
      outline-offset: -2px;
    }

    /* Passive open slot — a gap you can see, not a control. */
    .cm-slot--open {
      background: rgba(0, 0, 0, 0.16);
      box-shadow: inset 0 0 0 1px rgba(174, 191, 207, 0.05);
    }

    .cm-slot--open .cm-slot__mark {
      background: rgba(157, 176, 194, 0.035);
      box-shadow: inset 0 0 0 1px rgba(174, 191, 207, 0.045);
      color: #4f5862;
    }

    .cm-slot--open .cm-slot__name {
      color: #6d7782;
      font-size: 9.5px;
      letter-spacing: 0.14em;
      text-transform: uppercase;
    }

    /* Narrow rail: ~150px is the floor for a name plus a trailing cell.
       Below that, fall back to one column and let the list scroll. */
    @container cm-rail (max-width: 312px) {
      .cm-roster__list[data-layout="tdm"] {
        display: block;
      }

      .cm-roster__list[data-layout="tdm"] .cm-team + .cm-team {
        margin-top: 10px;
      }

      .cm-roster__list[data-layout="ffa"] .cm-slots {
        grid-template-columns: 1fr;
      }
    }

    /* ── Lobby: share strip ────────────────────────────────────────────
       Under the roster: you look for the code after you've seen who is in
       and that there's room. ── */
    .cm-share {
      display: flex;
      flex: 0 0 auto;
      align-items: center;
      gap: 8px;
      min-width: 0;
    }

    .cm-share__label {
      flex: 0 0 auto;
      color: #6f7a85;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 9px;
      font-weight: 800;
      letter-spacing: 0.16em;
      text-transform: uppercase;
    }

    .cm-code-chip {
      display: inline-flex;
      flex: 1 1 auto;
      min-width: 0;
      align-items: center;
      justify-content: space-between;
      gap: 10px;
      height: 30px;
      margin: 0;
      padding: 0 11px 0 13px;
      border: 0;
      outline: 0;
      border-radius: 5px;
      background: linear-gradient(180deg, rgba(var(--amber-rgb), 0.1), rgba(4, 7, 11, 0.7));
      box-shadow: inset 0 0 0 1px rgba(var(--amber-rgb), 0.22);
      color: #f1f4f6;
      cursor: pointer;
      font-family: Rajdhani, sans-serif;
      font-size: 17px;
      font-weight: 700;
      letter-spacing: 0.22em;
      line-height: 1;
      transition: background 150ms ease, box-shadow 150ms ease, color 150ms ease;
    }

    .cm-code-chip span {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .cm-code-chip i {
      flex: 0 0 auto;
      color: rgba(var(--amber-rgb), 0.7);
      font-size: 12px;
      transition: color 150ms ease;
    }

    .cm-code-chip:hover {
      background: linear-gradient(180deg, rgba(var(--amber-rgb), 0.2), rgba(4, 7, 11, 0.62));
      box-shadow: inset 0 0 0 1px rgba(var(--amber-rgb), 0.44);
    }

    .cm-code-chip:hover i { color: var(--amber-hot, #ffc252); }

    .cm-code-chip:focus-visible {
      outline: 2px solid var(--amber-hot, #ffc252);
      outline-offset: 2px;
    }

    /* 30px, not 36 — the code is read once and copied; it does not need to
       be the tallest thing between the roster and Start. Worth 6px of
       roster, which is what closes the gap on a full twelve. */
    .cm-share .cm-btn { flex: 0 0 auto; min-height: 30px; }

    /* ── Lobby: actions ──────────────────────────────────────────────
       The readiness line lives INSIDE the Start slab as a subtitle — the
       same title-over-subtitle shape Quick Play uses — so the CTA states
       what it will run and what is blocking it in one object. ── */
    .cm-actions {
      display: grid;
      flex: 0 0 auto;
      grid-template-columns: minmax(0, 1fr) auto;
      align-items: stretch;
      gap: 7px;
    }

    .cm-start,
    .cm-wait { min-height: 50px; }

    .cm-start {
      flex-direction: column;
      gap: 5px;
      padding: 0 12px;
    }

    .cm-start__title {
      font-size: 15px;
      letter-spacing: 0.1em;
      line-height: 1;
    }

    .cm-start__sub {
      max-width: 100%;
      overflow: hidden;
      color: rgba(23, 16, 6, 0.72);
      font-family: Inter, system-ui, sans-serif;
      font-size: 9px;
      font-weight: 700;
      letter-spacing: 0.07em;
      line-height: 1;
      text-overflow: ellipsis;
      text-transform: uppercase;
      white-space: nowrap;
    }

    .cm-start:disabled .cm-start__sub { color: #7f8a95; }

    .cm-create { min-height: 46px; font-size: 14px; letter-spacing: 0.1em; }


    /* Primary action anchors to the pane floor. */
    .cm-pane > .cm-create { margin-top: auto; }
    .cm-leave { padding: 0 15px; }

    /* Guest waiting state — a plate, not a dead button. */
    .cm-wait {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 9px;
      clip-path: polygon(6px 0, 100% 0, calc(100% - 6px) 100%, 0 100%);
      background: rgba(4, 7, 11, 0.6);
      box-shadow: inset 0 0 0 1px rgba(171, 188, 204, 0.12);
      color: #939ea9;
      font-family: Rajdhani, Inter, sans-serif;
      font-size: 12px;
      font-weight: 800;
      letter-spacing: 0.12em;
      text-transform: uppercase;
    }

    .cm-wait::before {
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: #939ea9;
      content: "";
      animation: cm-signal 1.6s ease-in-out infinite;
    }

    /* ── Role gating ── */
    .cm-panel[data-cm-role="guest"] [data-cm-host-only] { display: none !important; }

    .cm-panel[data-cm-role="guest"] .cm-start,
    .cm-panel[data-cm-role="host"] .cm-wait { display: none; }

    /* Inside a live lobby, header Exit stays hidden — Leave drops to the
       Custom hub; the Quick Play slab is the full exit. */
    .cm-panel[data-cm-view="lobby"] .cm-exit { display: none; }

    @media (prefers-reduced-motion: reduce) {
      .cm-wait::before { animation: none; }
    }

