/* The board's own styles, shared by the board (index.html) and the public Loadouts page
   (loadouts/index.html), so the two read as one site. */
  :root {
    --ground: #0c1416; --hero-top: #132227; --panel: #121c20; --hair: #1d2b30; --hair-2: #16232a; --div: #2b3d43; --tick: #3a4f56; --track: #16232a; --fail: #4a6068;
    --text: #e9eeed; --text-2: #a4b3b3; --muted: #6d7f80;
    --green: #1de08c; --on-green: #0b0f11; --red: #e0463f; --amber: #e6b34a;
    --s1: #3987e5; --s2: #e8a33d; --s3: #58b368; --s4: #c77dd9; --s5: #4fb8c9; --s6: #e66767;
    --hud: 'Chakra Petch', 'Barlow', system-ui, sans-serif;
    --body: Barlow, system-ui, -apple-system, sans-serif;
    /* The page's two horizontal measurements, and the reason they are not two numbers and a
       breakpoint: a window between a phone and a full desktop is the common case, not the edge,
       and a gutter that steps from 32 to 20 at one width spends the whole range in between paying
       for space it does not have. Both shrink with the window, and stop shrinking at the width
       where they would start costing legibility. --gut is the page's left and right margin, the
       same on the header, the bands and the two columns, which is what keeps the figures in the
       hero lined up with the table under them. --gap is the masthead's own spacing. */
    --gut: clamp(20px, 2.4vw, 32px);
    --gap: clamp(11px, 1.4vw, 18px);
  }
  * { box-sizing: border-box; }
  html, body { margin: 0; background: var(--ground); color: var(--text); font: 14px/1.45 var(--body); }
  a { color: var(--green); text-decoration: none; } a:hover { color: #6ff0b8; }
  @keyframes pulse { 0%, 100% { opacity: 1 } 50% { opacity: .3 } }
  .num { font-family: var(--hud); font-variant-numeric: tabular-nums; }
  .board { max-width: 1400px; margin: 0 auto; }

  /* ---- hero ---- */
  /* Not overflow: hidden. Nothing inside this header sticks out of it — the dot pattern below is
     inset: 0 — and hiding the overflow clipped the one thing that is meant to hang past the bottom
     edge, the account menu, which lands on the board beneath it. */
  /* The header is the width of the window; only what it holds is the width of the board. A page
     capped at 1400px otherwise ends the gradient and the radar at the cap, and on a wide screen
     that reads as two black bars with the theme painted between them. */
  /* No rule at the foot. There used to be a green hairline here, and it undid the thing below it:
     the contours fade out over the last third so the header ends by running out rather than by
     stopping, and a 1px line puts the hard edge straight back. The gradient already lands on
     --ground, which is what the board is, so the header can simply stop being there. */
  .hero { position: relative; background: linear-gradient(180deg, var(--hero-top) 0%, var(--ground) 100%); }
  .hero::before { content: ""; position: absolute; inset: 0; pointer-events: none; background: repeating-radial-gradient(circle at 85% 30%, transparent 0 22px, rgba(255, 255, 255, .035) 22px 23px); }
  /* hero-topo.js draws the contour map over the same box, and only then are the rings stood down */
  /* Faded out at the foot, because the header is too short for its own gradient to do it: at full
     strength the contours run into the green rule and stop dead, which reads as a cut rather than
     as ground going out of frame. */
  .topo { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none;
          -webkit-mask-image: linear-gradient(180deg, #000 0 70%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0 70%, transparent 100%); }
  .hero.topo-on::before { display: none; }
  .hin { position: relative; max-width: 1400px; margin: 0 auto; padding: 22px var(--gut) 26px; }
  .top { display: flex; align-items: center; gap: var(--gap); flex-wrap: wrap; }
  .mark { font: 700 15px var(--hud); letter-spacing: 2px; text-transform: uppercase; display: flex; align-items: center; gap: 10px; white-space: nowrap; }
  .tri { width: 12px; height: 12px; background: var(--green); clip-path: polygon(50% 0, 100% 100%, 0 100%); display: inline-block; flex: none; }
  /* The name with what it is underneath: "Sitrep" alone says nothing to somebody arriving from an
     invite link, and the game's name is the word they would search for. */
  .mark .nm { display: flex; flex-direction: column; gap: 3px; }
  .mark:has(.nm) { align-items: flex-start; }
  .mark .tri { margin-top: 3px; }
  .mark .sub { font: 500 11px var(--body); letter-spacing: .2px; text-transform: none; color: var(--muted); white-space: nowrap; }
  .vdiv { width: 1px; height: 18px; background: var(--div); flex: none; }
  /* The right-hand half of the masthead: what is being shown, over what window, for whom. It is
     pushed to the end by its own auto margin rather than by a spacer element, so that when the row
     runs out of width the whole group wraps as one and stays right-aligned on its new line. */
  .ctl { display: flex; align-items: center; gap: var(--gap); margin-left: auto; flex-wrap: wrap; justify-content: flex-end; }
  .modes { display: flex; gap: 2px; font: 600 12px var(--hud); text-transform: uppercase; letter-spacing: .6px; }
  .modes button { border: 0; padding: 6px 14px; background: #1a2a30; color: var(--text-2); font: inherit; cursor: pointer; text-transform: inherit; letter-spacing: inherit; }
  .modes button.on { background: var(--green); color: var(--on-green); }
  .ranges { display: flex; gap: var(--gap); font: 600 12px var(--hud); text-transform: uppercase; letter-spacing: .6px; color: var(--muted); }
  .ranges button, .link { border: 0; background: none; padding: 0 0 3px; color: inherit; font: inherit; cursor: pointer; text-transform: inherit; letter-spacing: inherit; border-bottom: 2px solid transparent; }
  .ranges button.on { color: var(--green); border-bottom-color: var(--green); }
  /* The board's heartbeat, at the end of the line it dates rather than in the corner of the
     masthead: "LëgällyBlind · net income · today · updated 14:32" is one sentence, and the time is
     the end of it. It takes the eyebrow's size, tracking and case and only its own colour, so it
     joins that line instead of sitting beside it — and the corner it left is ~100px the masthead
     now keeps for the tab bar. */
  .status { color: var(--muted); white-space: nowrap; }
  /* The dot that joins the two belongs to the line it ends, not to the clock. Carried by the clock
     it led the wrapped line on a narrow window, where it read as a bullet rather than as a join;
     and a module's eyebrow, which the clock stands down from, would have to remember to drop it. */
  .eyebrow:has(.status:not([hidden])) #eyebrow::after { content: "·"; margin-left: 6px; }

  /* account control, top right — the "you are logged in" corner */
  .acct { position: relative; }
  .acct .chip { display: flex; align-items: center; gap: 9px; border: 0; background: none; padding: 3px 0; cursor: pointer; color: var(--text); font: 600 13px 'Barlow', sans-serif; }
  .acct .chip:hover .nm { color: var(--green); }
  .acct .ava { width: 24px; height: 24px; flex: none; display: grid; place-items: center; background: var(--hair-2); border: 1px solid var(--hair); color: var(--text-2); font: 700 12px var(--hud); text-transform: uppercase; }
  .acct .nm { max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .acct .dot { width: 7px; height: 7px; flex: none; background: var(--muted); }
  .acct .dot.ok { background: var(--green); animation: pulse 2s infinite; }
  .acct .dot.warn { background: var(--amber); }
  .acct .dot.bad { background: var(--red); }
  .acct a.signin { display: inline-flex; align-items: center; gap: 8px; background: var(--green); color: var(--on-green); font: 700 11px var(--hud); letter-spacing: 1px; text-transform: uppercase; padding: 7px 13px; text-decoration: none; }
  .acct a.signin:hover { filter: brightness(1.08); }

  /* The boards list makes this panel as tall as the player has boards, so it is capped at what the
     window can show and scrolls past that — a menu taller than the screen has an unreachable end. */
  .menu { position: absolute; right: 0; top: calc(100% + 10px); z-index: 60; width: min(300px, calc(100vw - 40px)); max-height: calc(100vh - 90px); overflow-y: auto; background: var(--panel); border: 1px solid var(--hair); padding: 16px; text-align: left; }
  .menu .hd { display: flex; align-items: center; gap: 11px; }
  .menu .hd .ava { width: 34px; height: 34px; font-size: 14px; }
  .menu .hd b { display: block; font: 700 15px 'Barlow', sans-serif; color: var(--text); }
  .menu .hd span { font-size: 11px; color: var(--muted); }
  .menu .msg { margin: 13px 0 0; font-size: 13px; line-height: 1.5; color: var(--text-2); }
  .menu .meta { margin-top: 9px; font-size: 11px; color: var(--muted); }
  .menu .mi { margin-top: 15px; padding-top: 13px; border-top: 1px solid var(--hair); display: grid; gap: 11px; }
  .menu .mi a, .menu .mi button { border: 0; background: none; padding: 0; text-align: left; cursor: pointer; color: var(--text-2); font: 600 12px var(--hud); letter-spacing: .8px; text-transform: uppercase; text-decoration: none; }
  .menu .mi a:hover, .menu .mi button:hover { color: var(--text); }
  .menu .mi button.bad { color: var(--red); }
  .menu .mi button.bad:hover { filter: brightness(1.2); }
  .menu .go { background: var(--green); color: var(--on-green); padding: 8px 12px; text-align: center; }
  .menu .go:hover { filter: brightness(1.08); color: var(--on-green); }
  /* The boards this player is on. A list rather than a dropdown: there will never be many, and the
     one you are looking at should be visible without opening anything. */
  .menu .grp { margin-top: 14px; padding-top: 13px; border-top: 1px solid var(--hair); }
  .menu .grp > b { display: block; font: 600 10px var(--hud); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); margin-bottom: 8px; }
  .menu .grp .g { display: flex; width: 100%; align-items: baseline; justify-content: space-between; gap: 10px; background: none; border: 0; border-left: 2px solid transparent; color: var(--text-2); font: 400 13px 'Barlow', sans-serif; text-align: left; padding: 6px 0 6px 9px; cursor: pointer; }
  .menu .grp .g:hover { color: var(--text); background: var(--hair-2); }
  .menu .grp .g.on { color: var(--text); border-left-color: var(--green); }
  .menu .grp .g span { font: 400 11px 'Barlow', sans-serif; color: var(--muted); white-space: nowrap; }
  .menu .grp .gact { display: flex; gap: 8px; margin-top: 9px; }
  .menu .grp .gact button { flex: 1; background: var(--hair-2); border: 1px solid var(--hair); color: var(--text-2); font: 400 11px 'Barlow', sans-serif; padding: 6px 4px; cursor: pointer; }
  .menu .grp .gact button:hover { color: var(--text); border-color: var(--div); }
  .menu .grp .gown { margin: 9px 0 0; padding: 8px 9px; background: var(--hair-2); border-left: 2px solid var(--tick); }
  .menu .grp .gcode { font: 400 11px 'Barlow', sans-serif; color: var(--muted); }
  .menu .grp .gcode b { margin-left: 7px; font: 600 14px var(--hud); letter-spacing: 3px; color: var(--text); }
  .menu .grp .gbtn { display: flex; gap: 6px; margin-top: 7px; }
  .menu .grp .gbtn button { flex: 1; background: none; border: 1px solid var(--hair); color: var(--text-2); font: 400 11px 'Barlow', sans-serif; padding: 5px 4px; cursor: pointer; }
  .menu .grp .gbtn button:hover { color: var(--text); border-color: var(--div); }
  .menu .grp .gmem { display: flex; flex-direction: column; gap: 3px; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--hair); }
  .menu .grp .gmem span { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font: 400 12px 'Barlow', sans-serif; color: var(--text-2); }
  .menu .grp .gmem button { background: none; border: 0; color: var(--muted); font: 400 11px 'Barlow', sans-serif; padding: 0; cursor: pointer; }
  .menu .grp .gmem button:hover { color: var(--red); }
  .menu .grp .gleave { display: block; width: 100%; margin-top: 9px; background: none; border: 0; color: var(--muted); font: 400 11px 'Barlow', sans-serif; text-align: left; padding: 2px 0 0 9px; cursor: pointer; }
  .menu .grp .gleave:hover { color: var(--red); }
  .menu .grp .gf { display: flex; gap: 6px; margin-top: 9px; }
  .menu .grp .gf input { flex: 1; min-width: 0; background: var(--hair-2); border: 1px solid var(--hair); color: var(--text); font: 400 12px 'Barlow', sans-serif; padding: 6px 7px; }
  .menu .grp .gf button { background: var(--green); border: 0; color: var(--on-green); font: 600 11px var(--hud); letter-spacing: .5px; padding: 6px 11px; cursor: pointer; }
  .menu .grp .ge { margin-top: 7px; font-size: 11px; line-height: 1.4; color: var(--red); }

  /* An invite link that has just been made: copied to the clipboard, and shown here as well, since
     the clipboard is invisible and a link you can read is a link you can check before you send it. */
  .menu .lk { margin-top: 14px; padding-top: 13px; border-top: 1px solid var(--hair); }
  .menu .lk b { display: block; font: 600 10px var(--hud); letter-spacing: 1px; text-transform: uppercase; color: var(--green); margin-bottom: 7px; }
  .menu .lk input { width: 100%; box-sizing: border-box; background: var(--hair-2); border: 1px solid var(--hair); color: var(--text); font: 400 11px 'Barlow', sans-serif; padding: 7px 8px; }
  .menu .lk .code { margin-top: 7px; font-size: 11px; color: var(--text-2); }
  .menu .lk .code b { font: 600 13px var(--hud); letter-spacing: 2px; color: var(--green); }
.menu .lk span { display: block; margin-top: 7px; font-size: 11px; line-height: 1.45; color: var(--muted); }
  /* The headline takes its own line. Beside the cells it claimed a fixed ~480px and never gave
     any of it back, and with .board capped at 1400px that left the six cells under 810px between
     them — which is how "+4.63M" ended up across its divider. Full width they get 200px each. */
  .statrow { display: grid; grid-template-columns: 1fr; gap: 22px; margin-top: 28px; }
  /* The headline's own line is two columns, and the right one belongs to whichever tab is open:
     the big number never moves, and a tab that has a second thing worth saying at a glance says it
     in the space beside it that was empty anyway. A tab with nothing to say leaves it empty, and
     :empty then collapses the column so the layout is exactly what it was before. */
  .headline { display: grid; grid-template-columns: 1fr auto; gap: 40px; align-items: end; }
  .headline .aside:empty { display: none; }
  .eyebrow { font: 600 12px var(--hud); letter-spacing: 2px; text-transform: uppercase; color: var(--green); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
  .eyebrow i { width: 7px; height: 7px; background: var(--green); display: inline-block; animation: pulse 2s infinite; }
  .big { font: 700 96px/1 var(--hud); letter-spacing: -1px; font-variant-numeric: tabular-nums; margin-top: 14px; white-space: nowrap; }
  /* What the big number is, when the number alone does not say it. The board's own headline names
     itself in the eyebrow and leaves this empty, which collapses it to nothing. */
  .bigsub { font: 600 12px var(--hud); letter-spacing: 2px; text-transform: uppercase; color: var(--text-2); margin-top: 12px; }
  .bigsub:empty { display: none; }
  /* auto-fit rather than a hard column per cell: a cell can never be squeezed narrower than the
     numeral inside it, so cells wrap to a second row instead of a value spilling across the
     hairline that separates them. */
  .cells { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); border-left: 1px solid var(--div); }
  .cell { padding: 0 20px; border-right: 1px solid var(--div); min-width: 0; }
  .cell .v { font: 700 30px var(--hud); color: var(--green); font-variant-numeric: tabular-nums; white-space: nowrap; }
  .cell .k { font-size: 12px; text-transform: uppercase; letter-spacing: 1px; color: var(--text-2); margin-top: 2px; }
  /* The sample a headline came from: AI kills beside operator kills, deaths beside a K/D. */
  .cell[data-scroll] { cursor: pointer; }
  .cell .s { font: 600 11px var(--hud); letter-spacing: .5px; color: var(--muted); margin-top: 5px; }
  /* Two figures in the slot one used to have. The tile is a left-aligned stack and stays one: the
     pair sits on the value's own line, split by the same hairline that divides the cells themselves,
     so the second tier reads as the next column rather than as a second thing in this one. Baseline
     alignment, not centres — the numbers are what the eye runs along, and they are different widths. */
  .cell .twin { display: flex; align-items: baseline; }
  .cell .twin > span { display: block; padding-right: 15px; }
  .cell .twin > span + span { padding-left: 15px; border-left: 1px solid var(--hair); }
  .cell .twin .tv { display: block; font: 700 26px var(--hud); color: var(--green); font-variant-numeric: tabular-nums; line-height: 1.12; }
  .cell .twin .tl { display: block; font: 600 10px var(--hud); letter-spacing: 1.2px; text-transform: uppercase; color: var(--muted); margin-top: 2px; }
  /* Three tiers is the tight case everywhere, not only on a phone: the hero is six cells across a
     1400px cap, so a cell is under 200px on any laptop, and three figures with a word under each
     want more than that at full size. The figures step down and the labels give up most of their
     letter-spacing — the alternative is abbreviating Normal to N, and a tier you have to decode is
     worse than a tier set two points smaller. */
  .cell .twin.n3 .tv { font-size: 20px; }
  .cell .twin.n3 .tl { font-size: 9px; letter-spacing: .4px; }
  .cell .twin.n3 > span { padding-right: 8px; }
  .cell .twin.n3 > span + span { padding-left: 8px; }

  /* ---- roster ---- */
  .roster { border-bottom: 1px solid var(--hair); }
  /* The squad is the strip's title rather than a card in it: adding every player together is one
     more way to read the same row of people, not a fifth person to stand beside them — and as a
     card it cost a full column that the four real names were being squeezed out of. */
  .rhead { display: flex; align-items: baseline; gap: 12px; padding: 14px 24px 0; }
  .allsq { border: 0; background: none; padding: 0 0 4px; cursor: pointer; display: inline-flex; align-items: baseline;
           gap: 12px; flex-wrap: wrap; text-align: left; border-bottom: 2px solid transparent; color: var(--muted); }
  .allsq .lbl { font: 700 13px var(--hud); letter-spacing: 2px; text-transform: uppercase; }
  .allsq .sum { font-size: 12px; color: var(--muted); display: inline-flex; gap: 12px; flex-wrap: wrap; }
  .allsq b { font: 700 13px var(--hud); color: var(--text-2); font-variant-numeric: tabular-nums; }
  .allsq:hover { color: var(--text-2); }
  .allsq:hover b { color: var(--text); }
  .allsq.on { color: var(--green); border-bottom-color: var(--green); }
  .allsq.on b { color: var(--green); }
  .rgrid { display: grid; grid-template-columns: repeat(var(--n, 1), 1fr); }
  /* The card lays itself out from its own width, not the window's — how much room it has depends
     on how many people are on the board as much as on the screen, and a four-player squad on a
     laptop gives each card less than a phone gives one. Under 250px the name stops sharing a line
     with the state beside it, which is where the name was being cut to "JAMA…" to keep "LOGGED
     OUT" on the same line. */
  .pl { display: flex; gap: 14px; padding: 16px 24px; border-right: 1px solid var(--hair); position: relative; min-width: 0; container-type: inline-size; }
  @container (max-width: 250px) {
    .pl .nm { flex-wrap: wrap; }
    .pl .nm span:first-child { flex: 1 1 100%; }
  }
  .pl .bar { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; }
  .pl .ava { width: 52px; height: 52px; flex: none; border: 1px solid var(--div); background: repeating-linear-gradient(135deg, #1a2a30 0 5px, #15232a 5px 10px); object-fit: cover; }
  .pl .body { flex: 1; min-width: 0; }
  .pl .nm { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
  .pl .nm span:first-child { font: 600 16px var(--body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .pl .st { font: 600 10px var(--hud); text-transform: uppercase; letter-spacing: 1px; white-space: nowrap; }
  .pl .ln { display: flex; gap: 14px; margin-top: 6px; font-size: 12px; color: var(--text-2); flex-wrap: wrap; }
  .pl .ln b { font: 700 15px var(--hud); color: var(--text); font-variant-numeric: tabular-nums; }
  .pl[data-focus] { cursor: pointer; }
  .pl[data-focus]:not(.on) { opacity: .5; }
  .pl[data-focus]:not(.on):hover { opacity: .85; background: var(--hair-2); }
  .pl.on { background: var(--hair-2); }

  /* ---- full-width bands ---- */
  .band { padding: 22px var(--gut); border-bottom: 1px solid var(--hair); }
  .band .items { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); border-left: 1px solid var(--div); }
  .band .it { padding: 0 20px; border-right: 1px solid var(--div); min-width: 0; margin-bottom: 8px; }
  .band .it .v { font: 700 22px var(--hud); color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; }
  .band .it .k { font-size: 12px; text-transform: uppercase; letter-spacing: 1px; color: var(--text-2); margin-top: 2px; line-height: 1.3; }
  .band .it .k b { color: var(--text); font-weight: 600; }
  /* The operator's head, inline with their name in the expanded raid table, sized to the text
     it sits in. A mark beside a label, never instead of it. */
  .ophead { width: 16px; height: 16px; object-fit: cover; vertical-align: -3px; margin-right: 5px; background: var(--hair-2); }
  /* A band tile with art is the roster tile's shape: the same 52px square, the same hairline and
     the same hatched backing when the picture is missing, with the numbers stacked beside it
     rather than under it. The column has to be wider than a bare band's to hold both. */
  .band .items.has-art { grid-template-columns: repeat(auto-fit, minmax(212px, 1fr)); }
  .band .items.has-art .it { display: flex; gap: 14px; align-items: stretch; }
  /* The art sets the height and the numbers fill it, so every tile in the band is one block
     rather than a picture with a ragged column beside it. Cover, because the source is a square
     head and this is taller than it is wide. */
  .band .it .art { width: 62px; flex: none; align-self: stretch; object-fit: cover; border: 1px solid var(--div);
    background: repeating-linear-gradient(135deg, #1a2a30 0 5px, #15232a 5px 10px); }
  .band .it .bd { flex: 1; min-width: 0; }
  .band .it .tr { margin-top: 10px; max-width: 240px; }
  .band .it .sub { font: 600 11px var(--hud); letter-spacing: .5px; color: var(--muted); margin-top: 7px; }
  /* Zero Dam - Easy and Zero Dam - Normal are not the same raid, so the difficulty rides along
     with the name instead of being averaged away into one "Zero Dam". */
  .band .it .diff { color: var(--amber); }

  /* ---- the board's one bar: the whole track is the sample, the fill is the share that got out.
     A rate reads the same at two raids and at a hundred and thirty-nine; the count says which. ---- */
  .tr { height: 10px; background: var(--fail); position: relative; overflow: hidden; }
  .tr i { position: absolute; top: 0; bottom: 0; left: 0; display: block; }
  .tr i.f { box-shadow: 2px 0 0 var(--ground); }
  .gauge { display: grid; gap: 9px; }
  .gauge .g { display: grid; grid-template-columns: 74px 1fr 46px; gap: 11px; align-items: center; font-size: 13px; }
  .gauge .g .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-2); }
  .gauge .g .v { font: 600 13px var(--hud); text-align: right; font-variant-numeric: tabular-nums; }
  .legend { display: flex; gap: 16px; flex-wrap: wrap; font: 600 10px var(--hud); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); margin: -2px 0 11px; }
  .legend i { display: inline-block; width: 9px; height: 9px; margin-right: 6px; vertical-align: 0; }
  .mod-label { font: 700 13px var(--hud); letter-spacing: 2px; text-transform: uppercase; color: var(--text-2); margin-bottom: 12px; }
  .empty { font-size: 13px; color: var(--muted); }
  .empty .gatelink { color: var(--green); text-decoration: none; border-bottom: 1px solid rgba(29, 224, 140, .45); }
  .empty .gatelink:hover { border-bottom-color: var(--green); }

  /* ---- the private-board gate: what a visitor without a session sees instead of an empty board ---- */
  .gate { padding: 64px var(--gut) 72px; border-bottom: 1px solid var(--hair); text-align: center; }
  .gate h2 { font: 700 22px var(--hud); letter-spacing: 2px; text-transform: uppercase; margin: 0 0 14px; color: var(--text); }
  .gate p { max-width: 560px; margin: 0 auto 8px; font-size: 14px; line-height: 1.6; color: var(--text-2); }
  .gate p.fine { font-size: 12px; color: var(--muted); }
  .gate .go { display: inline-block; margin-top: 22px; padding: 11px 22px; background: var(--green); color: var(--on-green);
              font: 700 12px var(--hud); letter-spacing: 2px; text-transform: uppercase; text-decoration: none; }
  .gate .go:hover { filter: brightness(1.08); }
  /* the connect flow lives in here now, so the gate stops being a signpost and starts being the thing */
  .gate .cflow { max-width: 600px; margin: 28px auto 0; text-align: left; }
  .gate .cflow .step:last-child { border-bottom: 0; }
  body.gated .statrow, body.gated .roster, body.gated .band, body.gated .cols, body.gated .nudge,
  body.gated .modes, body.gated .ranges, body.gated .acct-div, body.gated .status,
  body.gated .tabs, body.gated .pane { display: none; }
  /* the gate IS the connect flow now, so the header's way in would only be a second door to it */
  body.gated .acct a.signin { display: none; }
  /* With the board hidden there is no dense column of numbers for the map to sit behind and nothing
     to read but one narrow strip of instructions, so here the map is the page rather than a band at
     the top of it: pinned to the window, at full strength all the way down, with the gate and the
     footnote lifted over it. (The canvas measures its own box, so this is the only instruction it
     needs.) The header keeps its gradient and its green rule, which now read as a horizon line
     across ground that carries on below. */
  body.gated .topo { position: fixed; z-index: 0; -webkit-mask-image: none; mask-image: none; }
  body.gated .gate, body.gated footer { position: relative; z-index: 1; }
  body.gated .gate { border-bottom: 0; }

  /* ---- tabs ----
     One tab per page of the board. "Match data" is the board itself and is always there; the rest
     are registered by the module files loaded before app.js, so a season ending is a deleted script
     tag and a deleted file rather than an edit to this page. The bar hides itself while only one
     tab exists: a single tab is not a choice. */
  /* Full-bleed across the hero rather than inset in it: the rule under the tabs has to reach both
     edges, or the bar reads as one more filter in the masthead instead of as the page you are on. */
  /* The page switch sits in the masthead beside the logo, in the slot the mode filter used to hold:
     which board you are looking at is the first choice, not one more filter on the data below. Same
     segmented shape as the filters it now outranks, one size up, so the family is still obvious. */
  /* flex: none — the bar does not give up width. Left shrinkable it folded its own buttons onto a
     second row while the controls beside it stayed put, which turns the one thing that says where
     you are into the thing that looks broken. It holds its line; the group on the right moves. */
  .tabs { display: flex; gap: 2px; flex-wrap: wrap; flex: none; font: 700 13px var(--hud); text-transform: uppercase; letter-spacing: 1.4px; }
  /* A tab can also be a link: Loadouts is a page of its own, open to anybody, so on the board its
     tab is an <a> to it and on that page the board's tab is an <a> back. Same shape either way. */
  .tabs button, .tabs a { border: 0; background: #1a2a30; text-decoration: none; display: inline-block; color: var(--text-2); padding: 8px clamp(11px, 1.2vw, 16px); font: inherit;
                 text-transform: inherit; letter-spacing: inherit; cursor: pointer; }
  .tabs button:hover, .tabs a:hover { color: var(--text); }
  .tabs button.on, .tabs a.on { background: var(--green); color: var(--on-green); }
  /* A filter that only means something on one tab belongs to that tab. Operations and Warfare are
     two shapes of the same match data and the card collection has neither, so the switch sits with
     the figures it changes — directly above the headline — and is absent on tabs it cannot move.
     The explicit display: flex would otherwise beat the hidden attribute, hence the [hidden] rule. */
  .panebar { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; margin-top: 22px; }
  .panebar[hidden] { display: none; }
  .pane { display: none; } .pane.on { display: block; }
  /* The range buttons pick a time window, and the mode buttons pick Operations or Warfare. Both
     belong to the match data; a tab that is not range-scoped says so by dimming them rather than
     by removing them, so the masthead does not change shape when you switch tabs. */
  .top .quiet { opacity: .28; pointer-events: none; }

  /* ---- body ---- */
  .cols { display: grid; grid-template-columns: 1.2fr .8fr; }
  .left { padding: 22px var(--gut); border-right: 1px solid var(--hair); min-width: 0; }
  .right { padding: 22px var(--gut); display: grid; gap: 26px; align-content: start; min-width: 0; }
  .feedhead { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 14px; gap: 12px; flex-wrap: wrap; }
  .feedhead .mod-label { margin: 0; }
  .note { font-size: 12px; color: var(--muted); }
  .mod-label .note { text-transform: none; letter-spacing: 0; font-weight: 400; margin-left: 4px; }
  .note b { color: var(--green); font-family: var(--hud); }
  .row { display: grid; grid-template-columns: 54px 4px 1fr auto auto; gap: 14px; align-items: center; padding: 9px 0; border-bottom: 1px solid var(--hair-2); cursor: pointer; }
  .row:hover { background: rgba(255, 255, 255, .015); }
  .row .t { font: 600 12px var(--hud); color: var(--muted); align-self: start; padding-top: 2px; }
  .row .t .d { display: block; font-size: 10px; letter-spacing: .5px; margin-top: 3px; opacity: .75; }
  .row .rail { height: 34px; display: flex; flex-direction: column; }
  .row .rail i { flex: 1; display: block; }
  .row .l1 { font-size: 15px; } .row .l1 b { font-weight: 600; }
  .row .tag { font: 600 11px var(--hud); text-transform: uppercase; letter-spacing: 1px; margin-left: 8px; }
  .row .l2 { font-size: 12px; color: var(--muted); }
  /* Operator kills are the ones that mean something; AI kills are a body count. Two lines,
     the real number first, so the eye never adds them together by accident. */
  .row .kl { font: 600 13px var(--hud); color: var(--text-2); white-space: nowrap; text-align: right; line-height: 1.35; }
  .row .kl span { display: block; }
  .row .kl .ai { color: var(--muted); font-size: 11px; }
  .row .kl em { font-style: normal; font-size: 10px; letter-spacing: .5px; color: var(--muted); }
  .row .nt { font: 700 16px var(--hud); font-variant-numeric: tabular-nums; min-width: 100px; text-align: right; white-space: nowrap; }
  .good { color: var(--green); } .bad { color: var(--red); } .warn { color: var(--amber); } .neutral { color: var(--text-2); }
  .det { padding: 8px 0 12px 72px; border-bottom: 1px solid var(--hair-2); }
  .det table { width: 100%; border-collapse: collapse; font-size: 12px; }
  .det th { font: 600 10px var(--hud); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); text-align: left; padding: 3px 8px 5px 0; border-bottom: 1px solid var(--hair); }
  .det td { padding: 4px 8px 4px 0; border-bottom: 1px solid var(--hair-2); white-space: nowrap; }
  .det th.n, .det td.n { text-align: right; font-family: var(--hud); font-variant-numeric: tabular-nums; }
  .det .mate { color: var(--muted); }
  .more { margin-top: 12px; font: 600 12px var(--hud); text-transform: uppercase; letter-spacing: .6px; }
  .more .link { color: var(--green); }
  .chart svg { width: 100%; height: auto; display: block; }
  .chart .ax { font: 600 10px var(--hud); letter-spacing: .8px; fill: var(--muted); text-transform: uppercase; }
  .chart .zero { stroke: var(--div); stroke-width: 1.5; }
  .chart .med { stroke: var(--tick); stroke-width: 1; stroke-dasharray: 4 4; }
  /* The running total itself, parked at the end of the line. Text ink, never a series colour:
     the line is already carrying the above/below-median encoding. */
  /* The running total, parked at the end of the line and riding it as new raids come in. Real
     HTML, not SVG text: the plot's viewBox is squeezed, and squeezed numerals get unreadable.
     Text ink, never a series colour — the line already carries the above/below-median encoding. */
  .chart { position: relative; }
  .chart .endv { position: absolute; transform: translateY(-50%); margin-left: 9px; white-space: nowrap;
    font: 700 13px var(--hud); font-variant-numeric: tabular-nums; color: var(--text); pointer-events: none; }
  .chart .cross { stroke: var(--tick); stroke-width: 1; }
  .foot { display: flex; justify-content: space-between; gap: 12px; font: 600 10px var(--hud); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); margin-top: 8px; }
  /* Recent high-value items, newest first, reading left to right. A row that scrolls inside
     itself shows far more of them than a column in the sidebar ever did. */
  .reds { display: flex; gap: 0; overflow-x: auto; border-left: 1px solid var(--div); }
  /* The board's one horizontal scroller, wearing the board's own tokens: the platform default is
     a pale rounded pill, the only piece of chrome on the page that isn't ours. Styling the WebKit
     scrollbar also stops macOS hiding it until you scroll, which is the hint that there is more
     to the right. Square, like everything else here. */
  .reds::-webkit-scrollbar { height: 10px; }
  .reds::-webkit-scrollbar-track { background: var(--track); border-top: 1px solid var(--hair); }
  .reds::-webkit-scrollbar-thumb { background: var(--tick); }
  .reds::-webkit-scrollbar-thumb:hover { background: var(--fail); }
  /* Firefox has no scrollbar pseudo-elements and gets the colour through the standard properties
     instead. They are scoped away from Chromium, which drops every ::-webkit-scrollbar rule for
     an element the moment scrollbar-width or scrollbar-color is set on it — which would hand the
     rounded overlay pill straight back. */
  @supports not selector(::-webkit-scrollbar) {
    .reds { scrollbar-width: thin; scrollbar-color: var(--tick) var(--track); }
  }
  .red { flex: 0 0 148px; padding: 0 16px; border-right: 1px solid var(--div); min-width: 0; }
  /* Gold and red are the game's own names for these two grades, so a card carries that colour as
     a 2px edge — a gradient rather than a border, which would shift the cell by a pixel, or a
     shadow, which this board does not use. The grade is written in the card as well: the colour
     is the fast read, not the only one. */
  /* One row of the board's standard bar, above the wall it describes: the track is every
     collectible red in the game and the fill is the share found. Same shape as the map and
     operator bands, so it reads without a second explanation. */
  .wallbar { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; }
  .wallbar .nm { font: 600 10px var(--hud); letter-spacing: 1px; text-transform: uppercase; color: var(--text-2); flex: 0 0 auto; }
  .wallbar .tr { flex: 1 1 auto; }
  .wallbar .v { font: 700 13px var(--hud); font-variant-numeric: tabular-nums; color: var(--text); flex: 0 0 auto; }
  #carried .red[data-grade="5"] { background: linear-gradient(to right, var(--amber) 0 2px, transparent 2px); }
  #carried .red[data-grade="6"] { background: linear-gradient(to right, var(--red) 0 2px, transparent 2px); }
  .red img, .red .ph { width: 44px; height: 44px; border: 1px solid var(--div); background: var(--panel); object-fit: contain; display: block; }
  .red .n { font: 600 13px var(--body); margin-top: 9px; line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .red .v { font: 700 15px var(--hud); color: var(--text); font-variant-numeric: tabular-nums; margin-top: 5px; }
  .red .m { font: 600 10px var(--hud); letter-spacing: .5px; text-transform: uppercase; color: var(--muted); margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* Daily private-room passwords: six numbers, so a row of them and nothing more. */
  .pws { display: flex; flex-wrap: wrap; gap: 0; border-left: 1px solid var(--div); }
  .pwi { flex: 1 1 130px; padding: 0 18px; border-right: 1px solid var(--div); min-width: 0; }
  .pwi .m { font: 600 10px var(--hud); letter-spacing: 1px; text-transform: uppercase; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .pwi .c { font: 600 22px 'Share Tech Mono', ui-monospace, monospace; letter-spacing: 2px; color: var(--text); margin-top: 4px; }
  .kv { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; font-size: 13px; }
  .kv span:first-child { color: var(--muted); text-transform: uppercase; letter-spacing: .6px; font: 600 11px var(--hud); padding-top: 2px; }
  .pw { font: 600 15px 'Share Tech Mono', ui-monospace, monospace; letter-spacing: 1px; }
  .kvt { width: 100%; border-collapse: collapse; font-size: 13px; }
  .kvt th { font: 600 10px var(--hud); letter-spacing: 1px; text-transform: uppercase; color: var(--muted); text-align: left; padding: 3px 10px 5px 0; border-bottom: 1px solid var(--hair); }
  .kvt td { padding: 5px 10px 5px 0; border-bottom: 1px solid var(--hair-2); }
  .tip { position: fixed; pointer-events: none; display: none; z-index: 10; background: #0a1012; border: 1px solid var(--div); color: var(--text); font: 12px var(--body); padding: 6px 9px; white-space: nowrap; }
  .tip b { font-family: var(--hud); }
  footer { color: var(--muted); font-size: 12px; text-align: center; padding: 20px; }
  /* The line that says whose game this is. It keeps the footer's own colour rather than stepping
     down to --fail, which lands around 2.8:1 on this ground: a disclaimer set too faint to read is
     both a dark pattern and a weaker disclaimer. Position and a point of size separate it instead. */
  footer .legal { margin-top: 10px; font-size: 11px; }
  .banner { margin: 22px var(--gut) 0; border-left: 3px solid var(--red); background: #1a1416; padding: 8px 10px; color: #f0d0d0; }
  .nudge { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; padding: 14px var(--gut); border-bottom: 1px solid var(--hair); color: var(--text-2); font-size: 14px; }
  .nudge b { color: var(--text); font-weight: 600; }
  .nudge button { border: 0; background: none; padding: 0; cursor: pointer; color: var(--green); font: 600 12px var(--hud); letter-spacing: 1px; text-transform: uppercase; }
  .nudge button:hover { color: #6ff0b8; }

  /* Narrow enough that the tab bar is on its own line under the wordmark whatever tabs are open,
     and a rule between two things on different lines is a mark with nothing on the other side. */
  @media (max-width: 700px) { .top > .vdiv { display: none; } }

  /* What is left in here is what a narrow window changes about the shape of a thing, not about the
     space around it: the gutters and the masthead's spacing are fluid above and need no step. */
  @media (max-width: 900px) {
    .hin { padding: 18px var(--gut) 22px; }
    .big { font-size: 64px; }
    .headline { grid-template-columns: 1fr; gap: 22px; }
    /* Below this the bar is allowed to fold after all: a phone is narrower than four tab names,
       and a second row of buttons beats a row that runs off the side of the screen. */
    .tabs { flex: 0 1 auto; font-size: 12px; letter-spacing: 1.2px; }
    .tabs button, .tabs a { padding: 7px 12px; }
    .panebar { margin-top: 18px; }
    .cells { grid-template-columns: 1fr 1fr; } .cell { padding: 8px 16px; }
    /* Half a phone wide, two or three figures and a hairline between each: the number gives up the
       four pixels rather than the tile giving up the tier. */
    .cell .twin .tv { font-size: 21px; }
    .cell .twin > span { padding-right: 11px; } .cell .twin > span + span { padding-left: 11px; }
    /* Half a phone is narrower still. Dropping the third tier is not an option: a range with Hard
       in it is exactly the range worth splitting. */
    .cell .twin.n3 .tv { font-size: 18px; }
    .cell .twin.n3 > span { padding-right: 6px; } .cell .twin.n3 > span + span { padding-left: 6px; }
    .rgrid { grid-template-columns: 1fr 1fr; }
    .rhead { padding: 12px 16px 0; }
    .pl { padding: 14px 16px; }
    .cols { grid-template-columns: 1fr; } .left { border-right: 0; border-bottom: 1px solid var(--hair); }
    .left, .right, .band { padding: 20px var(--gut); }
    /* Long money columns used to be pushed off the right edge: let every cell shrink. */
    .row { grid-template-columns: 44px 4px 1fr auto auto; gap: 9px; }
    .row > div, .row .nt { min-width: 0; }
    .row .l2 { overflow-wrap: anywhere; } .row .tag { white-space: nowrap; }
    .row .nt { font-size: 15px; } .row .kl { font-size: 12px; }
    .det { padding-left: 0; }
    .gauge .g { grid-template-columns: 62px 1fr 42px; gap: 9px; }
    .band .it .tr { max-width: none; }
    .pwi { flex: 1 1 96px; padding: 0 12px; }
    .pwi .c { font-size: 18px; }
    .red { flex-basis: 132px; padding: 0 12px; }
    .banner { margin: 20px var(--gut) 0; } .nudge { padding: 12px var(--gut); }
    /* The controls have a line to themselves long before this width, and on a narrow one they wrap
       inside it — a rule left standing at the head of a wrapped line divides nothing. */
    .acct-div { display: none; }
  }
