/* ============================================================================
   style.css: the page rules the Ledger kit (ledger/kit.css) does not own yet: the shell grid, docs, the wizards,
   the range popover and a few page leftovers. Every colour, size, space and radius is a ledger/tokens.css name
   (loaded after this sheet); this sheet defines no colour of its own (WP10 retired the old "Lighthouse gold"
   token blocks and their tint/edge/graph/tip names).
   ========================================================================= */
:root {
  color-scheme: dark;
  /* the two family names the old rules use: the one face (tokens.css --font) */
  --font-display: var(--font);
  --font-body: var(--font);
}
:root[data-theme="light"] { color-scheme: light; }

* { box-sizing: border-box; }
/* stable gutter: short and tall pages keep the same centred column — no shift on nav */
html { scrollbar-gutter: stable; }
/* Column layout so the footer is pinned to the bottom of the VIEWPORT on a short
   page and pushed below the fold on a long one — never floating mid-screen. */
body { margin: 0; background: var(--bg); color: var(--text);
  font: var(--fs-body)/1.6 var(--font-body);
  min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; }
code, pre { font-family: var(--font-body); font-variant-numeric: tabular-nums; }
h1, h2, h3, .wizh { font-family: var(--font-display); }
/* links are ink with a hairline underline (the .dr-link treatment); gold is reserved for the one
   .primary per view, the Overview's finding glyph and an emphasised series. Chrome and card anchors
   draw their own affordance (fill, border, tab underline) and carry no text underline. */
a { color: var(--text); text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 2px; }
a:hover { text-decoration-color: var(--text); }
.seg a, .footer a, a.btn { text-decoration: none; }

/* One visible focus treatment for every interactive thing (was missing entirely). */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--accent-ink); outline-offset: 2px;
}

/* ------------------------------------------------------------------ shell -- */
/* WP1, the Ledger shell (STYLEGUIDE-r2 §5, lofi shell-*). One grid for every width and every page: the 64px top bar
   over columns 1-12, the section nav in columns 1-2, the content in 3-12, the drawer (when one is open) a third grid
   track in 9-12 that the content reflows beside. The three old layouts (the ≤1399 gutter sidebar, the ≥1400 fixed
   rail, the ≤720 strip) are gone. Nothing here is sticky except the nav and the drawer inside their own track, so
   a sticky element has nothing to clear. app.js GG.shell.update() paints the pieces, keyed, in place. */
:root {
  /* one column of the 12 at the current width, and the nav's two of them (168px floor) */
  --gg-col: calc((min(100vw, 1440px) - 2 * var(--s7) - 11 * var(--s6)) / 12);
  --gg-nav-w: max(168px, calc(2 * var(--gg-col) + var(--s6)));
}
.jsload { display: none; }
html[data-theme] .jsload { display: block; }
.spacer { flex: 1; }
.caret { color: var(--muted); display: inline-flex; align-items: center; flex: none; }
.caret svg { display: block; }

/* the chrome sits outside any .gg-view, so it takes the kit's base type itself: body 13/20 400 tabular (Y-06) */
.gg-top, .gg-foot, .gg-nav, .gg-sections, .gg-skip { font-family: var(--font); font-size: var(--fs-body); line-height: var(--lh-body);
  font-weight: var(--w-body); font-variant-numeric: var(--nums-body); }
.gg-top button, .gg-nav button, .gg-sections button { font-variant-numeric: var(--nums-body); }
/* skip link: off screen until it has focus, then the first thing on the page (L-20) */
.gg-skip { position: absolute; left: var(--s4); top: 0; z-index: var(--z-modal); transform: translateY(-120%);
  display: inline-flex; align-items: center; height: var(--h-ctl); padding: 0 var(--s3); background: var(--panel);
  color: var(--text); border: 1px solid var(--line-ctl); border-radius: var(--r-ctl); text-decoration: none; }
.gg-skip:focus { transform: none; }
main:focus { outline: none; }

/* the top bar: lockup + Home + Docs | ORG › GAME (centred) | status + account (SH-01) */
.gg-top { display: grid; grid-template-columns: minmax(max-content, 1fr) minmax(0, max-content) minmax(max-content, 1fr);
  grid-template-areas: "left where right"; align-items: center; column-gap: var(--s6); height: var(--topbar-h);
  width: 100%; max-width: 1440px; margin: 0 auto; padding: 0 var(--s7); border-bottom: 1px solid var(--line); background: var(--bg); }
.gg-top-left { grid-area: left; display: flex; align-items: center; gap: var(--s6); min-width: 0; }
.gg-top-right { grid-area: right; display: flex; align-items: center; justify-content: flex-end; gap: var(--s4); min-width: 0; }
.gg-sitenav { display: flex; align-items: center; gap: var(--s4); }
.gg-sitelink { display: inline-flex; align-items: center; height: var(--h-ctl-sm); color: var(--dim); font-size: var(--fs-body);
  font-weight: var(--w-label); line-height: var(--lh-body); text-decoration: none; white-space: nowrap; }
.gg-top .gg-brand { height: var(--h-ctl-sm); }
.gg-sitelink:hover { color: var(--text); text-decoration: none; }
/* the current site page: text, underlined, never gold (SH-03) */
.gg-sitelink[aria-current="page"] { color: var(--text); text-decoration: underline; text-decoration-color: var(--text);
  text-decoration-thickness: 1px; text-underline-offset: 4px; }

/* where you are: ORG › GAME, each a 28px menu button, the names ellipsize first (M-08) */
.gg-where { grid-area: where; display: flex; align-items: center; justify-content: center; gap: var(--s1); min-width: 0; }
.gg-where:empty { display: none; }
.gg-where .gg-pop { min-width: 0; }
.gg-where-item { display: inline-flex; align-items: center; gap: var(--s1); min-width: 0; height: var(--h-ctl-sm); margin: 0; padding: 0 var(--s2);
  background: none; border: 0; border-radius: var(--r-ctl); color: var(--text); font-family: var(--font); font-size: var(--fs-body);
  font-weight: var(--w-body); line-height: var(--lh-body); font-variant-numeric: var(--nums-body); white-space: nowrap; cursor: pointer; }
span.gg-where-item { cursor: default; }
button.gg-where-item:hover, button.gg-where-item[aria-expanded="true"] { background: var(--panel2); }
.gg-where-name { min-width: 0; max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gg-where-item > .gg-icon { color: var(--dim); flex: none; }
.gg-where-sep { display: inline-flex; color: var(--dim); flex: none; }
.gg-live-dot { width: 6px; height: 6px; border-radius: var(--r-disc); background: var(--dim); flex: none; }
.gg-live-dot[data-live] { background: var(--good); }

/* status: "Updated just now" + the Auto-refresh menu, game views only (SH-02) */
.gg-status { display: flex; align-items: center; min-width: 0; }
.gg-status[hidden], .gg-sections[hidden], .gg-nav[hidden] { display: none; }
.arctl { display: inline-flex; align-items: center; gap: var(--s3); white-space: nowrap; }
.fresh { font-size: var(--fs-caption); line-height: var(--lh-caption); color: var(--dim); white-space: nowrap; }
.fresh .short { display: none; }
.gg-status-updated { display: inline-flex; align-items: center; gap: var(--s1); color: var(--dim); font-size: var(--fs-caption); line-height: var(--lh-caption); }
.arctl.arfail .gg-status-updated { color: var(--bad); }
.arpickslot { display: inline-flex; }
.arpickslot[hidden] { display: none; }
.arctl.busy .arpick svg { animation: arspin .8s linear infinite; }
@keyframes arspin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .arctl.busy .arpick svg { animation: none; } }

/* account: the initial in a 24px disc + caret; the popover holds who, links, the theme, Sign out */
.gg-account { display: flex; align-items: center; }
.gg-user { display: inline-flex; align-items: center; gap: var(--s1); height: var(--h-ctl); margin: 0; padding: 0 var(--s1);
  background: none; border: 0; border-radius: var(--r-ctl); color: var(--dim); font-family: var(--font); font-size: var(--fs-body);
  line-height: var(--lh-body); font-weight: var(--w-body); font-variant-numeric: var(--nums-body); cursor: pointer; }
.gg-user:hover, .gg-user[aria-expanded="true"] { background: var(--panel2); color: var(--text); }
/* the account opener's disc (lofi: 24px, round); scoped to .gg-user so the kit's .gg-avatar (loaded later) cannot
   restyle it (review r4 L1-01) */
.gg-user .gg-avatar { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 24px; height: 24px; border-radius: var(--r-disc);
  background: var(--panel2); border: 1px solid var(--line-ctl); color: var(--text); font-size: var(--fs-caption); font-weight: var(--w-label); line-height: 1; }
.gg-account .gg-popover { min-width: 260px; }
.gg-acct-who { display: flex; flex-direction: column; gap: var(--s1); min-width: 0; }
.gg-acct-who .gg-strong { overflow-wrap: anywhere; }
.gg-acct-links { display: flex; flex-direction: column; margin: 0 calc(-1 * var(--s2)); }

/* the page: one grid. nav 1-2 | banner + main 3-12 | drawer 9-12 when open (S-08, SHT-01) */
.gg-page { display: grid; grid-template-columns: var(--gg-nav-w) minmax(0, 1fr); grid-template-rows: auto 1fr; column-gap: var(--s6);
  align-items: start; width: 100%; max-width: 1440px; margin: 0 auto; padding: var(--s6) var(--s7) var(--s8); flex: 1 0 auto; }
.gg-page > main { grid-column: 2; grid-row: 2; min-width: 0; width: auto; max-width: none; margin: 0; padding: 0; position: relative; }
.gg-page > #usagebanner { grid-column: 2; grid-row: 1; margin: 0 0 var(--s5); }
.gg-page > #gg-drawer-slot { grid-column: 3; grid-row: 1 / span 2; align-self: stretch; display: grid; align-content: start; min-width: 0; }
.gg-page > #gg-drawer-slot:empty { display: none; }
.gg-page:has(> #gg-drawer-slot:not(:empty)) { grid-template-columns: var(--gg-nav-w) minmax(0, 1fr) minmax(var(--drawer-min), var(--drawer-w)); }
/* no section nav (site pages, docs, auth): the content takes columns 2-11 */
.gg-page[data-nav="none"] { grid-template-columns: var(--gg-col) minmax(0, 1fr) var(--gg-col); }
.gg-page[data-nav="none"]:has(> #gg-drawer-slot:not(:empty)) { grid-template-columns: var(--gg-col) minmax(0, 1fr) minmax(var(--drawer-min), var(--drawer-w)); }

/* the section nav: icon + word, the current item the 2px accent-ink bar flush left on panel2 (SH-04, M-01) */
.gg-nav { grid-column: 1; grid-row: 1 / span 2; position: sticky; top: var(--s4); min-width: 0; }
.gg-nav-head { display: none; }
.gg-nav-list { display: flex; flex-direction: column; gap: 0; margin: 0; padding: 0; list-style: none; }
.gg-nav-list a { position: relative; display: flex; align-items: center; gap: var(--s2); height: var(--h-ctl); padding: 0 var(--s3);
  color: var(--dim); font-size: var(--fs-body); font-weight: var(--w-label); line-height: 1; text-decoration: none; white-space: nowrap;
  border-radius: 0; }
.gg-nav-list a:hover { color: var(--text); text-decoration: none; }
.gg-nav-list a > .gg-icon { flex: none; }
.gg-nav-word { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.gg-nav-list a[aria-current="page"] { color: var(--text); background: var(--panel2); }
.gg-nav-list a[aria-current="page"]::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: var(--mark-w); background: var(--accent-ink); }
.gg-nav-dot { width: 6px; height: 6px; border-radius: var(--r-disc); background: var(--text); flex: none; }
.gg-sections { display: none; }

/* the footer: lockup + © year indie.io | Privacy, Terms (SH-12) */
.gg-foot { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--s2) var(--s6); width: 100%;
  max-width: 1440px; margin: 0 auto; padding: var(--s5) var(--s7); border-top: 1px solid var(--line); color: var(--dim);
  font-size: var(--fs-caption); line-height: var(--lh-caption); }
.gg-foot-brand { display: flex; align-items: center; gap: var(--s3); }
.gg-foot-legal { display: flex; align-items: center; gap: var(--s4); }
.gg-foot-legal a { display: inline-flex; align-items: center; height: var(--h-ctl-sm); color: var(--dim); text-decoration: none; }
.gg-foot-legal a:hover { color: var(--text); text-decoration: underline; }

/* the custom range popover (CT-06, lofi range-picker): presets, one or two months, the draft, Cancel + Apply */
.gg-rangepop.gg-popover { width: max-content; max-width: min(560px, calc(100vw - 2 * var(--s4))); }
.gg-rangepop .rp-main { display: flex; flex-direction: column; gap: var(--s3); }
.gg-rangepop .rp-months { display: flex; gap: var(--s4); }
.gg-rangepop .rp-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s1); height: var(--h-ctl-sm); }
.gg-rangepop .rp-pg { width: var(--h-ctl-sm); flex: none; }
.gg-rangepop .rp-month { flex: 1; text-align: center; font-size: var(--fs-body); font-weight: var(--w-label); color: var(--text); }
.gg-rangepop .rp-grid { display: grid; grid-template-columns: repeat(7, 32px); gap: 0; margin: var(--s1) 0 0; justify-content: center; }
.gg-rangepop .rp-dow { display: flex; align-items: center; justify-content: center; height: 24px; font-size: var(--fs-caption); color: var(--dim); }
.gg-rangepop .rp-d { width: 32px; height: 32px; padding: 0; margin: 0; border: 0; border-radius: var(--r-ctl); background: none; color: var(--text);
  font-family: var(--font); font-size: var(--fs-body); font-weight: var(--w-body); line-height: var(--lh-body); font-variant-numeric: var(--nums-body); cursor: pointer; }
.gg-rangepop .rp-d:hover:not([disabled]) { background: var(--panel2); }
.gg-rangepop .rp-d.today { text-decoration: underline; text-underline-offset: 3px; }
.gg-rangepop .rp-d.pv, .gg-rangepop .rp-d.mid { background: var(--panel2); border-radius: 0; }
.gg-rangepop .rp-d.end, .gg-rangepop .rp-d.end:hover { background: var(--text); color: var(--bg); }
.gg-rangepop .rp-d.from { border-radius: 4px 0 0 4px; }
.gg-rangepop .rp-d.to { border-radius: 0 4px 4px 0; }
.gg-rangepop .rp-d.from.to { border-radius: var(--r-ctl); }
.gg-rangepop .rp-d[disabled] { color: var(--muted); cursor: default; }
.gg-rangepop .rp-draft, .gg-rangepop .rp-note { margin: 0; font-size: var(--fs-body); line-height: var(--lh-body); font-variant-numeric: var(--nums-body); color: var(--dim); }
.gg-rangepop .rp-note:empty { display: none; }

/* ≤900 the bar is two 28px rows in its 64px (brand + links | account, then where | status): ORG › GAME and the
   status line no longer fit beside the links (200% zoom at 1440 lands here, L-26) */
@media (max-width: 900px) {
  .gg-top { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "left right" "where status";
    grid-template-rows: var(--h-ctl-sm) var(--h-ctl-sm); row-gap: var(--s1); align-content: center; column-gap: var(--s3); padding: 0 var(--s4); }
  .gg-top[data-rows="1"] { grid-template-areas: "left right"; grid-template-rows: var(--h-ctl-sm); }
  .gg-top .gg-lockup { height: 20px; width: calc(20px * 342.6 / 64); }
  .gg-top-left { gap: var(--s3); }
  .gg-sitenav { gap: var(--s3); }
  .gg-top-right { display: contents; }
  .gg-account { grid-area: right; justify-self: end; }
  .gg-status { grid-area: status; justify-self: end; }
  .gg-user { height: var(--h-ctl-sm); }
  .gg-where { justify-content: flex-start; margin: 0 0 0 calc(-1 * var(--s2)); }
  /* popovers hung from the bar go full width under it */
  .gg-top .gg-pop { position: static; }
  .gg-top .gg-popover { position: fixed; top: calc(var(--topbar-h) + var(--s1)); left: var(--s4); right: var(--s4); max-width: none; }
  .gg-page { padding: var(--s6) var(--s4) var(--s8); }
  .gg-page[data-nav="none"] { grid-template-columns: 0 minmax(0, 1fr) 0; column-gap: 0; }
  /* a 400px drawer track would leave main ~160px wide here: the drawer lays over the page's right edge instead
     (the kit's body mount, from the slot), and the page keeps its own columns */
  .gg-page:has(> #gg-drawer-slot:not(:empty)) { grid-template-columns: var(--gg-nav-w) minmax(0, 1fr); }
  .gg-page[data-nav="none"]:has(> #gg-drawer-slot:not(:empty)) { grid-template-columns: 0 minmax(0, 1fr) 0; }
  .gg-page > #gg-drawer-slot { position: fixed; top: 0; right: 0; bottom: 0; z-index: var(--z-drawer); width: min(var(--drawer-w), 100%);
    display: flex; flex-direction: column; }
  .gg-page > #gg-drawer-slot > .gg-drawer { position: static; flex: 1 1 auto; max-height: none; min-width: 0; border-width: 0 0 0 1px;
    border-radius: 0; box-shadow: var(--shadow); }
}

/* Players and Sessions: Platforms and Builds side by side (views/data.js breakdownRow, Evan 2026-11-03). The two panels
   keep one height, so the row reads as one band; GG.split's own columns stack them where two do not fit */
.gg-split.pl-breakdowns { align-items: stretch; }
.gg-split.pl-breakdowns > .gg-split-part > .gg-section { flex: 1 1 auto; }

/* ≤600: the game alone on the second row; the nav behind "Sections", a full-height sheet (SH-05) */
@media (max-width: 600px) {
  /* Sessions at 390 (gate10 TB-08): Started keeps its one line without the weekday, and the cells take --s1 sides (the
     Show all cell none) so Started, Player, Duration, End and Show all fit the 309px card, no sideways scroll */
  .gg-table-wrap[data-key="sessions"] .pl-wd { display: none; }
  .gg-table-wrap[data-key="sessions"] .gg-table-cell.gg-table-cell { padding-left: var(--s1); padding-right: var(--s1); }
  .gg-table-wrap[data-key="sessions"] .gg-td-more.gg-table-cell { padding-left: 0; padding-right: 0; }
  .gg-table-wrap[data-key="sessions"] .gg-table-more > .gg-table-cell.gg-table-cell { padding: var(--s2); }
  /* the range keeps its six presets on one line at 390 (the lofi's range-picker-390): tabular 13/20 items at s3 overflow
     358px and the kit would fold them to a select with no Custom opener (kit-requests/wp1.md K5) */
  .gg-title-actions .gg-seg-item { padding: 0 var(--s2); }
  /* ORG › GAME both stay (menu-org opens from here too); the names ellipsize first, the carets go (M-08) */
  .gg-where { gap: 0; }
  .gg-where-item { padding: 0 var(--s1); }
  .gg-where-item > .gg-icon { display: none; }
  .gg-status-updated > .gg-icon { display: none; }
  /* the status line takes its short form ("Updated now", "Updated 4m ago") so ORG › GAME gets a fair share of the second
     row instead of clipping to "Nightl… › Lu…" beside the full "Updated just now" (r5 L1-13; §0 still ellipsizes the
     names first when even that does not fit) */
  .fresh .long { display: none; }
  .fresh .short { display: inline; }
  .gg-top-right, .gg-status .arctl { gap: var(--s2); }
  .gg-rangepop.gg-popover { position: fixed; top: var(--s4); left: var(--s4); right: var(--s4); width: auto; max-width: none;
    max-height: calc(100dvh - 2 * var(--s4)); overflow: auto; }

  .gg-page { display: block; padding: var(--s4) var(--s4) var(--s7); }
  .gg-page > #usagebanner { margin: 0 0 var(--s4); }
  .gg-sections { display: block; margin: 0 0 var(--s4); }
  .gg-sections[hidden] { display: none; }
  body[data-sheet] .gg-sections { visibility: hidden; }
  .gg-sections-btn { position: relative; display: inline-flex; align-items: center; gap: var(--s2); height: var(--h-ctl); margin: 0;
    padding: 0 var(--s3); background: var(--panel2); border: 0; border-radius: 0; color: var(--text); font-family: var(--font);
    font-size: var(--fs-body); font-weight: var(--w-body); line-height: var(--lh-body); font-variant-numeric: var(--nums-body); cursor: pointer; }
  .gg-sections-btn[data-gold]::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: var(--mark-w); background: var(--accent-ink); }
  .gg-sections-btn > .gg-icon:last-child { color: var(--dim); }
  .gg-nav { display: none; }
  .gg-nav[data-open] { display: flex; flex-direction: column; position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: var(--z-modal);
    padding: var(--s4); background: var(--bg); overflow: auto; }
  .gg-nav[data-open] .gg-nav-head { order: -1; display: flex; align-items: center; justify-content: space-between; height: var(--h-ctl); margin: 0 0 var(--s4); }
  .gg-nav-title { font-size: var(--fs-section); line-height: var(--lh-section); font-weight: var(--w-head); }
  .gg-nav[data-open] .gg-nav-list a { height: var(--row-h); }
  body[data-sheet] { overflow: hidden; }

  .gg-foot { flex-direction: column; align-items: flex-start; padding: var(--s4); }
}

/* --------------------------------------------------------------- layout -- */
/* A navigation that resolves fast should look instant; one that does not should look
   busy. 180ms is the threshold — below it nothing dims, so a local click never flashes. */
#app.pending { opacity: .45; transition: opacity var(--t-fade) linear; }
.sronly { position: absolute; width: 1px; height: 1px; margin: 0; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
/* An integer line box. At 1.6 the title was 38.4px tall, which put the heading — and
   therefore every block under it, and the sidebar lined up with them — on a half pixel.
   The page-title role is 22/1.2; 26px is that ratio rounded to whole pixels. */
h1 { font-size: var(--fs-title); line-height: 26px; margin: var(--s2) 0 var(--s1); font-weight: 600; }

/* THE PAGE'S CONTENT STARTS AT THE SAME HEIGHT IN EVERY SECTION.
   The title block owns the gap beneath it; the block after it must not add one of its
   own. Before this, that first block brought its own margin — 24px on Overview, 0 on
   Progression, 12 on the events hub — so the content, and the sidebar that lines up with
   it, started somewhere different in every section and the sidebar jumped by up to 41px
   as you moved between them. The :is() is what carries enough specificity to beat the
   single-class margins those blocks declare. */
main > :is(h1, .titlerow):first-child { margin-top: 0; margin-bottom: var(--s6); }
main > :is(h1, .titlerow):first-child + * { margin-top: 0; }
/* A subtitle is heading furniture, not content: whatever follows it does not get to add
   a margin either. */
main > :is(h1, .titlerow):first-child + :is(.sub, .crumb) + * { margin-top: 0; }
h2 { font-size: var(--fs-section); line-height: 1.3; margin: var(--s6) 0 var(--s2); font-weight: 600; }
h3 { font-size: var(--fs-section); line-height: 1.3; font-weight: 600; }

/* Integer line box, same reason as h1: a 20.8px subtitle put everything under it on a
   half pixel. */

.muted { color: var(--muted); }
.pad { padding: var(--s5); }
/* .notice, the inline warning slot under forms, drawn as the contract's info box (ui.js
   infoBox): section fill, one hairline, radius 4, padding 12 16, a 16px amber ring. */

.note { color: var(--muted); font-size: var(--fs-caption); line-height: 1.4; }
.small { font-size: var(--fs-caption); }
.b { font-weight: 600; }

/* -------------------------------------------------------------- controls -- */
/* ONE button family (primitives.md §1). The bare <button> is SECONDARY: transparent, one
   hairline, ink. `.primary` is the view's one gold forward action and an explicit opt-in;
   `.ghost` dismisses and navigates inside a surface; `.danger` is the destructive confirm.
   Two heights, 32 (default) and 28 (`.sm`: filter rows, table rows, overlay
   headers); radius 4; weight 500; hover is one token step with no transition and no
   transform; the focus ring is the global :focus-visible rule. `a.btn` (ui.js btn() with
   href) is the same thing drawn on an anchor. */
button, a.btn { background: transparent; color: var(--text); border: 1px solid var(--line);
  border-radius: var(--r-ctl); height: var(--h-ctl); padding: 0 var(--s3); font: 500 var(--fs-body)/18px var(--font-body);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: var(--s2); }

button:hover, a.btn:hover { background: var(--panel2); color: var(--text); text-decoration: none; }
button[disabled], a.btn[aria-disabled="true"] { opacity: .4; pointer-events: none; }
/* the display above beats the UA's [hidden]: Browse's "Load more" showed under an empty list (2026-10-18) */
button[hidden], a.btn[hidden] { display: none; }
button.primary, a.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
button.primary:hover, a.btn.primary:hover { background: var(--accent); border-color: var(--accent-ink); color: var(--on-accent); }
button.ghost, a.btn.ghost { border-color: transparent; color: var(--dim); }
button.ghost:hover, a.btn.ghost:hover { background: var(--panel2); color: var(--text); border-color: transparent; }
button.danger, a.btn.danger { color: var(--bad); border-color: var(--bad); }
button.danger:hover, a.btn.danger:hover { background: var(--panel2); color: var(--bad); border-color: var(--bad); }
button.sm, a.btn.sm { height: var(--h-ctl-sm); padding: 0 var(--s2); gap: var(--s1); }
   /* WP8: delete — an alias of the default size */
input, textarea, select { background: var(--panel); color: var(--text); border: 1px solid var(--line);
  border-radius: var(--r-ctl); padding: var(--s2) var(--s3); font: var(--fs-body)/18px var(--font-body); }
/* Focus is ONE idea. This rule used to kill the outline and recolour the border instead,
   which made a text field the only control in the product announcing focus in a different
   language from the button beside it. The global :focus-visible ring covers inputs too, so
   there is nothing left to say here — a ring AND a recoloured border is the same mistake
   wearing the other hat. */
input::placeholder, textarea::placeholder { color: var(--muted); }
.toolbar { display: flex; gap: var(--s3); align-items: center; margin: var(--s3) 0; flex-wrap: wrap; }

/* ------------------------------------------------- panels + shared cards -- */

/* note panel: panel chrome without .panel's padding/margin (call sites bring their own) */

/* Players / Sessions: the list's Export CSV at the right end of its panel title (stacked: right-aligned) */

/* Events: Browse rows / Aggregate, then the event-type catalogue link at the row's right end */
.toolbar.evmodes { margin: 0 0 var(--s4); }
.toolbar.evmodes > .seg { margin: 0; }

.lastref { margin-left: auto; color: var(--muted); font-size: var(--fs-caption); align-self: center; }

/* ---------------------------------------------------- story + insights --- */

/* ---------------------------------------------------------------- tiles -- */

/* P2: figures on the page surface, no box; the hairline between them keeps the pair legible */

/* a heading and its chart on the page surface (Players); .row2 pairs them without the panel frame */

/* The lo-fi's .stat-card reads LABEL -> NUMBER -> DELTA. The markup emits the value
   first (several call sites, some with a toggle appended), so the order is fixed
   here rather than in JS: .l first, .v second, anything else after, in DOM order. */

/* tile(value, label, definition, sub, href): with an href the value IS the link (linkFig) */

/* Two lines are reserved whether or not the label needs them, so every big number
   in the row lands on one baseline — real metric names wrap, the lo-fi's didn't. */

 

/* An emphasised metric tile is NOT a gating state — it must not borrow the orange. */

.up { color: var(--good); } 

/* ------------------------------------------------------ charts + layout -- */
svg text { fill: var(--muted); font: var(--fs-caption)/1.4 var(--font-body); font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------- funnel -- */

/* ---------------------------------------------------------------- world -- */

.zone { border: 1px solid var(--line); border-radius: var(--r-ctl); padding: var(--s3); position: relative;
  cursor: pointer; min-height: 104px; }
a.zone { display: block; color: inherit; text-decoration: none; }


/* --------------------------------------------------------------- compare -- */

/* --------------------------------------------------------------- tables -- */
table.data { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
table.data th { text-align: left; color: var(--muted); font-weight: 500; font-size: var(--fs-caption);
  line-height: 1.4; padding: var(--s2) var(--s3); border-bottom: 1px solid var(--line); }
/* Every data cell is the cell role: 12px, 400, tabular figures — ids, versions, dates and
   counts line up as machine data in the one face. */
table.data td { text-align: left; padding: var(--s2) var(--s3); border-bottom: 1px solid var(--line);
  font: 400 var(--fs-cell)/1.5 var(--font-body); font-variant-numeric: tabular-nums; }
table.data tr:hover td { background: var(--panel2); }

.docs table.data td { font: var(--fs-cell)/1.5 var(--font-body); }
.docs table.data td.key { font-weight: 600; }
code.inline { background: var(--panel2); padding: 0 var(--s2); border-radius: var(--r-ctl); font-size: var(--fs-cell); }
pre { background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-ctl);
  padding: var(--s3) var(--s3); overflow-x: auto; }

/* ------------------------------------------------------------ games list -- */
/* Grid items default to min-width:auto, so a name with no break opportunity widened the
   item's min-content past its track: the card box stayed in its cell while the text ran
   under the next card and past the rail (Evan's "cut off" cards, 2026-09-24). min-width:0
   + overflow:hidden keep every string inside; titles are one line with an ellipsis and
   carry the full name in a title attribute. min(100%, 260px) keeps one column honest on
   narrow screens instead of forcing a 260px track into a 240px rail. */

/* Page titles and one-line labels that carry a user string: wrap the unbreakable, never
   push the page sideways. */
h1, h2, .wizh { overflow-wrap: anywhere; min-width: 0; }
.titlerow button { flex-shrink: 0; white-space: nowrap; }
select { max-width: 100%; }

table.data td { overflow-wrap: anywhere; }

/* -------------------------------------------------- pills / chips / tags -- */
/* One shared silhouette for every small status label; colour is the only variable. */

/* ------------------------------------------- per-game plans (v1.61.0) -- */
/* A month meter: label and used / cap on one line, a 6px track under it. The fill is calm (dim) under 80%,
   attention from 80% and red at the cap: never gold, so the page's one gold control stays the only gold. */

   /* #plan deep links clear the sticky topbar + game bar */

/* org page: a game card's plan tag and its tightest meter */

/* -------------------------------------------------------- settings/docs -- */

.docs { max-width: 780px; }
/* the kit's text classes carry no block margins (gg-text/gg-h/gg-bullets are margin: 0); the docs article is the
   one long-form page, so its rhythm lives here: a gap between blocks, more air above a heading than below it */
.docs > .gg-text, .docs > .gg-bullets { margin: var(--s3) 0; }
.docs > :first-child { margin-top: 0; }
.docs .gg-bullets { gap: var(--s2); }
.docs h2 { margin-top: var(--s6); margin-bottom: var(--s2); }
.docs h2[id] { scroll-margin-top: var(--s4); }   /* deep links clear the sticky topbar + game bar */
.codewrap { position: relative; margin: var(--s3) 0; }
.codeblock { background: var(--panel2); border: 1px solid var(--line); border-radius: var(--r-ctl);
  padding: var(--s3) var(--s4); font: var(--fs-cell)/1.55 var(--font-body); overflow-x: auto; white-space: pre;
  margin: 0; color: var(--text); }
.codewrap .codeblock { padding-right: var(--s8); }
.copybtn { position: absolute; top: 8px; right: 8px; height: var(--h-ctl-sm); padding: 0 var(--s2); font-size: var(--fs-cell); }
/* padding-right only pads the END of a sideways-scrolling block, so scrolled code slid under the floating Copy
   (2.4.0 release L2 MINOR-1): the button is opaque in its block's colour, and code never shows through it.
   The docs pages put Copy in a header row above the code instead (.docs .codehead), so nothing sits under it there. */
.codewrap > .copybtn { background: var(--panel2); }

/* docs (/docs, /g/<id>/docs): the page list on the left from 900px, a select above the page below
   that. The article is rendered from markdown by docs-md.js; these rules style its fixed output. */

/* docs reading size: body text at 15px, code at 13px and wrapped, so a long line never hides
   behind a sideways scroll (copy still takes the exact text) */
.docs p, .docs li { font-size: 15px; line-height: 1.6; }
/* the kit text classes keep the ledger body size inside the docs article (Y-06, Y-09: six sizes only) */
/* the empty-state and info-box bodies too: the docs not-found page drew its empty body at 15px (r6 L2 F09) */
.docs .gg-text, .docs .gg-bullets li, .docs .gg-empty-body, .docs .gg-info-text { font-size: var(--fs-body); line-height: var(--lh-body); }
.docs .gg-code-inline { font-size: var(--fs-cell); }
.docs pre code, .docs .codeblock { font-size: 13px; }
.docs .codeblock { white-space: pre-wrap; overflow-wrap: anywhere; }
.docs .onpage { border-left: 2px solid var(--line); padding: var(--s1) var(--s4); margin: var(--s3) 0 var(--s4); }
.docs .onpage ul { margin: var(--s1) 0; padding-left: var(--s5); }
.docs .onpage li { margin: var(--s1) 0; font-size: var(--fs-body); }

.docs [id] { scroll-margin-top: var(--s4); }
.docs h1 { margin-top: 0; }
.docs h3 { margin-top: var(--s5); margin-bottom: var(--s2); }
.docs li > p { margin: var(--s2) 0; }
/* a code in a table's first column is the key a reader scans for: keep it whole */
.docs table.data td:first-child code { white-space: nowrap; overflow-wrap: normal; }
/* other cells may still wrap a long code, but only where it cannot fit whole (a URL in a Default column) */
.docs table.data td:not(:first-child) code { overflow-wrap: break-word; }
/* inline code in prose and code headings sits just under the text size, not at the 12px cell size */
.docs p > code, .docs li > code, .docs h2 > code, .docs h3 > code { font-size: .87em; }
/* the underline has to show on a callout's panel in dark mode too */
.docs a { text-decoration-color: var(--dim); }
.docs a:hover { text-decoration-color: var(--text); }

.docs .codehead { display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
  padding: var(--s1) var(--s2) var(--s1) var(--s3); background: var(--panel); border: 1px solid var(--line); border-bottom: 0;
  border-radius: var(--r-ctl) var(--r-ctl) 0 0; }
.docs .codelang { font-size: var(--fs-caption); color: var(--dim); }
.docs .codehead .copybtn { position: static; }
.docs .codehead + .codeblock { border-radius: 0 0 var(--r-ctl) var(--r-ctl); padding-right: var(--s4); }
.docs .callout { border-left: 3px solid var(--line); background: var(--panel2); padding: var(--s1) var(--s4);
  border-radius: 0 var(--r-ctl) var(--r-ctl) 0; margin: var(--s4) 0; }
.docs .doctable { overflow-x: auto; margin: var(--s3) 0; }
.docs .docfold { border: 1px solid var(--line); border-radius: var(--r-ctl); padding: var(--s2) var(--s3); margin: var(--s3) 0; }
.docs .docfold summary { cursor: pointer; font-weight: 600; }
.docs-noscript-nav { margin-bottom: var(--s4); }
/* phones: a docs table becomes one block per row, each cell labelled with its column */
@media (max-width: 480px) {
  .docs table.data.stack, .docs table.data.stack tbody, .docs table.data.stack tr, .docs table.data.stack td { display: block; width: auto; }
  .docs table.data.stack thead { display: none; }
  .docs table.data.stack tr { border-bottom: 1px solid var(--line); padding: var(--s2) 0; }
  .docs table.data.stack tr:hover td { background: none; }
  .docs table.data.stack td { border: 0; padding: var(--s1) 0; }
  .docs table.data.stack td[data-label]::before { content: attr(data-label) ": "; color: var(--dim); }
}

/* height restated: the engine cards on /new are <button>s and would take the control height */

/* background restated: the same <button>s would go gold on hover */

/* -------------------------------------------------------- modals + toast -- */
/* Modals and popovers are the kit's (GG.modal, GG.popover in ledger/kit.css); nothing for them lives here. */
/* The layers: popover 30 · drawer 40 · the ≥1400 shell's rail 95 and top bar 100 · modal (and the full-size
   screenshot) 110 · tooltip and toast 120. A modal sits above the chrome: under it, the top bar and rail stayed
   live. The toast is the note box, fixed bottom-right, 320px, one at a time. */

.tooltip { position: fixed; pointer-events: none; z-index: 120; background: var(--panel); color: var(--text);
  border: 1px solid var(--line-firm); border-radius: var(--r-ctl); padding: var(--s1) var(--s2);
  font-size: var(--fs-caption); line-height: 1.4; max-width: 240px; }

/* -------------------------------------------------------------- wizards -- */

.wizh { font-size: var(--fs-title); line-height: 1.2; font-weight: 600; margin: var(--s4) 0 var(--s1); }
/* Two smaller ranks of the same heading. These used to be inline font-size overrides at
   19px and 17px — sizes that exist nowhere in the scale. */
.wizh.step { font-size: var(--fs-section); margin-top: var(--s1); }

/* the setup wizards are sheet modals (ui.js) at their own widths: the one place a modal is wider than 480 */

/* a chrome <button> must restate its hover background or it inherits the gold one */

/* agent-onboarding live rows */

/* Banners take the info-box paint: section fill, one hairline, no tints (F3). The role
   lives in the bold word, not the border. */

/* ----------------------------------------------------------- events hub -- */

/* ------------------------------------------- before/after evidence bars --- */

/* ------------------------------------------- gating grammar (the ORANGE) -- */
/* Gating owns --attention exclusively. Gold is brand chrome and never means
   "you have work to do", which is the collision this palette exists to fix. */

/* sample ghosts — NEVER name this `.ghost`, it collides with button.ghost and kills clicks */

/* step pills are the contract's tag: 20px, inset fill, radius 4 */

/* agent prompts inside gate CTAs and wizards wrap instead of clipping */
.emptybox .codeblock {
  white-space: pre-wrap; word-break: break-word; font-size: var(--fs-caption); }
/* Overview agent-flow CTA strip */

/* ------------------------------------------------- v1.10 nav support bits -- */
/* A view's heading and its one primary action share a row. */
/* The title grows; the buttons never shrink or wrap their labels — when they no longer
   fit beside a long title they drop to their own line instead of squeezing the h1. */
.titlerow { display: flex; align-items: center; gap: var(--s3) var(--s4); margin: 0 0 var(--s4); flex-wrap: wrap; }
.titlerow h1, .titlerow h2 { margin: 0; flex: 1 1 320px; }
.titlerow .spacer { flex: 1; }
/* Two modes of one task (Browse rows / Aggregate). A second-level CONTROL, not a
   second-level destination — which is why it sits in the page, not in the chrome. */
/* the same segmented control as .chips, drawn on anchors */
.seg { display: inline-flex; margin: 0 0 var(--s4); }
.seg a { height: var(--h-ctl-sm); padding: 0 var(--s3); border-radius: 0; border: 1px solid var(--line);
  background: var(--panel); display: inline-flex; align-items: center; font: 500 var(--fs-body)/18px var(--font-body); color: var(--dim); }
.seg a:first-child { border-radius: var(--r-ctl) 0 0 var(--r-ctl); }
.seg a:last-child { border-radius: 0 var(--r-ctl) var(--r-ctl) 0; }
.seg a + a { border-left-width: 0; }   /* adjacent segments share one border */
.seg a:hover { color: var(--text); background: var(--panel2); text-decoration: none; }
.seg a.on { background: var(--panel2); color: var(--text); }
/* Empty collection: the note box, left-aligned, where the content would have been (F3). */
/* collapsed time control, shown only under the 1080px breakpoint */
/* a chrome <button> must restate its hover background or it inherits the gold one */

/* ---------- login (Phase 1 auth) ---------- */

/* The drawn lockup, not the string — the sign-in card is the first brand surface a
   visitor sees, so it uses the same asset as the nav and the www site. */

/* Controls, not links: the shared 40px line box; hover restated (gold-hover trap). */

/* "Last used" rides inside the provider's own chrome, so it takes that chrome's ink
   (currentColor) rather than a site token — legible on Google white, GitHub black and
   Discord blurple alike, and never gold. */

/* Callback outcome (cancelled / provider / expired): informational, not an alarm —
   neutral panel, dim ink; .notice is red and reserved for real failures. */

/* Per-provider chrome — colours are the providers' official button specs:
   Google's light/dark sign-in buttons; GitHub's dark-mode chrome / brand black;
   Discord blurple. Must not be re-derived from site tokens. */
/* --- google --- */

/* --- github --- */

/* --- discord --- */

/* --- mock (dev) — dashed neutral, inherits 40px geometry --- */

/* ---------- Connected accounts (idn-list) ---------- */

/* Neutral, not gold: marking which email is the account's is a fact, not a CTA. */

/* Phone widths: a lone Connect stays inline; when the text and the actions can't share
   a line (two buttons), the actions wrap below, right-aligned. */

/* ---------- Phase 2: organizations ---------- */
/* dim org pill on game cards (all-games view only) */
/* user-menu org rows: check gutter + small tags */

/* account: slim org summary */

/* ---------- Phase 5: tracked insights + gate picker ---------- */
.tracked-box:empty { display: none; }
.tracked-box { margin-bottom: var(--s3); }

/* Activity log */

/* Alert rows */

/* Limits table */

/* Belldot: unseen alerts, on the Settings link. It sits at the end of its row like the Bugs dot (.sndot);
   absolutely positioned it had no positioned link to anchor to and floated at the rail's top-right corner. */

/* Hover restates */

/* Saved Queries */

/* Shared page */

/* Share dialog */

/* Funnel validation */

/* Funnel preview in shared view */

/* ── Health dots ──────────────────────────────────────────────────────────── */

/* ── Environment chips ────────────────────────────────────────────────────── */

/* environment chips are filter controls: 28px, hairline, radius 4, selected = inset fill */

/* ── Portfolio table ──────────────────────────────────────────────────────── */

/* ---------- Retention curve (retcurve) ---------- */
/* full content width, uniform scale — the 360px cap shrank a 1090-wide viewBox to a
   40px-tall strip; grid hairlines are solid, dashing reads as a threshold */
/* ---------- Retention heatmap grid (retgrid) ---------- */
/* ---------- Crash bar (crashbar) ---------- */
/* ---------- What's Next card (wnx) ---------- */
.wnx { position: relative; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-ctl);
  padding: var(--s3) var(--s4); margin: var(--s6) 0; }

/* ---------- Version compare (vcmp) ---------- */

/* ---------- Light theme overrides ---------- */

/* ---------- Hover states for buttons/links ---------- */

/* c3: crash tile direction tint (devx backlog) */
/* c5: topbar org badge (mock-5) */
/* -------------------------------------------------------- empty state -- */
/* The empty state is the note box where the content would have been (F3): app.js emptyState()
   returns ui.js infoBox("note", …) carrying .emptybox, which dresses its agent-prompt details
   and docs line below. */
.emptybox details { margin-top: var(--s3); font-size: var(--fs-cell); color: var(--muted); }
.emptybox details summary { cursor: pointer; color: var(--dim); display: inline-block; padding: var(--s1) var(--s2); margin-left: calc(-1 * var(--s2));
  border: 1px solid transparent; border-radius: var(--r-ctl); list-style: none; user-select: none; }
.emptybox details summary::-webkit-details-marker { display: none; }
.emptybox details summary:hover { color: var(--text); border-color: var(--line); background: var(--panel2); }
.emptybox details .codeblock { text-align: left; margin-top: var(--s3); }
.emptybox details[open] { text-align: left; width: 100%; max-width: 640px; }
.emptybox .ebdocs { font-size: var(--fs-cell); color: var(--muted); }
/* wizard kicker: the credential note moved out of the crowded head row */

.emptybox .ebdocs a { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; }
.emptybox .ebdocs a:hover { color: var(--text); }
/* the details copy button is a secondary action — never a second gold */
.emptybox details button { margin-top: var(--s2); }
.emptybox .ebnote { margin-top: var(--s2); max-width: 72ch; font-size: var(--fs-caption); color: var(--muted); line-height: 1.4; }

/* ------------------------------------------- org page game-card kebab menu -- */

/* org identity marks (avatars): img when a logo is set, initial letter otherwise.
   Rounded square = org, circle = user — the two 26px marks share the right cluster. */
.oav { display: inline-flex; align-items: center; justify-content: center; flex: none;
  border-radius: var(--r-ctl); background: var(--panel2); border: 1px solid var(--line);
  object-fit: cover; }
.oav-i { color: var(--dim); font-weight: 600; font-size: var(--fs-caption); }

/* charts 2026-09-23: full-width stack on the Overview, legend row, bar strip */
/* wraps: a row of platform toggles (Performance's FPS legend) ran past the card at 360 */

/* ------------------------------------------------------------ welcome -- */

/* ---------------------------------------- context switcher: text, left cluster -- */


/* an org mark next to its name gets air, everywhere the two sit inline */
h1 > .oav { margin-right: var(--s3); vertical-align: middle; }

/* Phone widths: key rows wrap their buttons, and data tables scroll inside their own box
   instead of widening the page. */
@media (max-width: 480px) {
  
  table.data { display: block; overflow-x: auto; max-width: 100%; }
}
/* A key row's text column must be allowed to shrink (grid 1fr defaults to min-content),
   and on phones the buttons drop under the text; cells keep whole words there so a wide
   table scrolls in its box instead of breaking an email into one letter per line. */

@media (max-width: 480px) {
  
  table.data td { overflow-wrap: normal; }
}

/* Invite-only beta: the request form under the sign-in buttons. */

/* the GitHub field's placeholder is long; it gets its own row so it reads in full */

/* Action columns in the old tables (kept from the retired ≥1400 shell, now at every width): a last cell holding a
   button or link is right-aligned; .stack (the docs tables, docs-md.js) keeps its prose links where they are. */
main table.data:not(.stack) td:last-child:has(button), main table.data:not(.stack) td:last-child:has(a) { text-align: right; white-space: nowrap; width: 1%; }
main table.data:not(.stack):has(td:last-child button) th:last-child, main table.data:not(.stack):has(td:last-child a) th:last-child { text-align: right; }

/* -- Overview "Player engagement" chart (design B3, 2026-10-07): drawEngagement() in app.js.
   SVG text needs classes: `svg text` (above) beats fill/font-size attributes. -- */

/* the SVG keeps its aspect at every width: no height attribute to letterbox below 1400 px, and no
   max-height cap (400/480/600 px elsewhere) to letterbox it on wide screens */

/* ≥1400px lifts the Share button into the first chart panel's title row (a6 block): keep the
   right-aligned headline clear of it. */

/* ---------- Bug reports (seventh tab, DESIGN-C, 2026-10-08) ----------
   Tokens only. Every control stays 32px; the only solid amber on these screens is the
   active nav and the screen's one primary button. Later rules win, so this block sits last. */

/* the cap banner: an attention tint, 40px, never amber-filled */

/* a segmented control built from buttons: 26px inside the seg's 32px */
.seg > button { background: transparent; color: var(--dim); border: 1px solid transparent;
  border-radius: var(--r-ctl); padding: var(--s1) var(--s4); font-size: var(--fs-cell); line-height: 18px; font-weight: 500; }
.seg > button:hover { background: transparent; color: var(--text); border-color: transparent; }
.seg > button.on { background: var(--panel2); color: var(--text); }
.seg.small { margin: 0; }
.seg.small > button { padding: var(--s1) var(--s3); }
/* Screen 1 */

/* high is bright ink, never orange: orange marks at most one element per screen (R10) */

/* low is a ring in --muted (>= 3:1 on panel in both themes), so it never reads as the
   unrated dot (--line) and is told from medium by shape as well as colour */

/* phones: the 260px AI column left the title 0px wide and pushed the age off the row; title and age share
   the first line, the AI state takes the second */

/* in a list it is one row of many: neutral, never orange per row */

/* status badges: new reads brightest but stays neutral (never orange per row); resolved is good; the rest dim */

/* Screen 2 */

.bugs-bulk { display: flex; align-items: center; gap: var(--s2); min-height: 40px; box-sizing: border-box; padding: 0 var(--s3);
  margin: 0 0 var(--s2); border: 1px solid var(--line); border-radius: var(--r-ctl); background: var(--panel2); font-size: var(--fs-cell); }
.bugs-bulk[hidden] { display: none; }

.bugs-table td, .bugs-table th { height: 40px; box-sizing: border-box; padding-top: 0; padding-bottom: 0; vertical-align: middle; }

/* fixed columns: twelve of them fit the 984 content column, the title takes what is left,
   and every cell is one line with the full value in its title attribute (ellipsis policy) */
.bugs-table { table-layout: fixed; width: 100%; min-width: 1040px; }   /* scrolls inside .scroll-x below ~1250px, as Browse does */
.bugs-table td, .bugs-table th { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  
  
  

/* Screen 3 and 4 */

/* ---- Bugs polish (v1.46.0): figure strip, hot-spot list, one orange, mono for machine values only ---- */

/* a cluster's count: the number is the machine value, its words are prose */

/* the other tracked alerts on the Bugs page: their chip is quiet, the hot-spot count holds the one orange */

/* zone tiles: a gold-tint heat scale, never the orange family */

/* tables: prose in the body face; zone ids and versions are the machine values that stay mono */
table.data.bugs-table td { font-family: var(--font-body); font-size: var(--fs-body); }

  
/* fix1 #5: a header never truncates: it may wrap to two lines inside the 40 px row, words whole */
.bugs-table th { white-space: normal; text-overflow: clip; overflow: visible; line-height: 14px; overflow-wrap: normal; hyphens: none; }
/* cluster detail */

/* report detail: a missing screenshot is one quiet line, not a large empty frame */

.shot-full { position: fixed; inset: 0; z-index: 110; background: var(--backdrop); display: flex;
  align-items: center; justify-content: center; cursor: zoom-out; }
.shot-full img { max-width: 96vw; max-height: 96vh; }

/* the report status: a staged pick waits for Apply */

/* a section whose read failed: the copy and its Retry */

/* phones: the clusters header and the breakdown title wrap their segmented control onto its
   own line instead of pushing the page sideways */

/* ---------------------------------------------------------------------------------------------------------
   Bugs setup (BG-D, v1.46): the page a game sees until its first bug report (readiness needs / waiting).
   Checklist card + example report card. Ported from concepts/BG-D/BG-D.css (bga-/bgd- → bsu-).
   Surfaces: ground (--bg), lit (--panel: checklist + example card), well (--bg inset: the code). One amber: .bsu-amber.
   --------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------- header -- */

/* ------------------------------------------------------------------ grid -- */

/* --------------------------------------------------------- the checklist -- */

/* the rail: one segment per step, joined; it starts and ends on a pill's centre */

   /* fix2 C: no one-word last line ("… send one / report") */

/* code: the "well" — the page ground sunk into the lit list */

/* fix1 #20: step 1's guide is a link drawn as the primary button (button metrics: 32 px tall) */

/* a failed copy's message drops under the code instead of covering what has to be selected */

/* --------------------------------------------- the agent line + footers -- */

/* ------------------------------------------------- the example card -- */

/* desktop: the card grows to the checklist's height; the five rows share the extra space evenly */

/* each row's icon sits in a small well tile */

/* ----------------------------------------------------------- narrow -- */

/* prod additions over the mock: icons arrive as <span class="bsu-svg"><svg>; the waiting state's done step;
   the unknown-engine variant (three labelled switches); the example card's player quote */

/* unknown engine: the checklist carries three switches, far taller than the card; the card keeps its own height */

/* screen-reader-only text (live status for copy buttons) */

/* ---------- Feedback (eighth tab) + Settings → Report intake (feedback P0, 2026-10-13) ----------
   Tokens only; the one-amber rule holds: the selected row is a panel tint, never amber. */

/* ---------- Feedback phase 2 (2026-10-17): Inbox | Surveys | Cohorts, the feedback block in Settings ----------
   One-amber rule: nothing here is amber. Errors and an over-budget bar are --bad; the budget bar is ink. */

/* the survey editor */

.svf-msg { color: var(--bad); font-size: var(--fs-cell); line-height: 1.4; margin: var(--s1) 0; overflow-wrap: anywhere; }
.svf-msg[hidden] { display: none; }

/* Settings: the feedback prompt */

/* Cohorts */

/* phones: the survey and cohort tables become one block per row, each cell labelled */

/* inspector drawer links that open a record (drawer.js): ink, underlined, never gold (was drawer.css) */
.dr-link { color: var(--text); text-decoration: underline; text-decoration-color: var(--line); text-underline-offset: 2px; }
.dr-link:hover { text-decoration-color: var(--text); }
.dr-link.btn { text-decoration: none; }
