/* ===== VGP Registry =========================================================================
   ONE stylesheet for /registry and /registry/console/<console>. Deliberately a file and not two
   inline <style> blocks: the .pop-modal component had just been un-triplicated across three files
   when these pages were written, and starting them the same way is how that happens again.

   Colours come from theme.css variables only, so both themes work without a second set of rules.
   ========================================================================================== */

/* 248px, not 208: the console counts read "N collected" now, which is ~47px wider than the bare
   number was and clipped "PlayStation Portable" in the old rail. The 40px comes off the board, whose
   widest content is a handle and already wraps. */
.reg-wrap { display: grid; grid-template-columns: 248px 1fr; gap: 22px; align-items: start; }


/* ---- sidebar ---------------------------------------------------------------------------- */
.reg-side { position: sticky; top: 14px; }
.reg-side-h { font-family: 'Oxanium', monospace; font-weight: 800; font-size: 0.68rem;
    letter-spacing: 1.6px; color: var(--text-muted, #8a97a6); padding: 0 0 8px 2px; }
/* The MOST-OWNED <CONSOLE> GAMES heading. It borrowed .reg-side-h, which is sized and coloured to
   label a rail of links, not to head a section of the page: 0.68rem and muted grey.
   0.68 x 1.1 = 0.748rem, and #111 rather than pure black -- at 800 weight with 1.6px tracking true
   black renders heavier than the h1 above it, so a sub-heading would outshout the title. */
/* --text-strong IS #111111 in light, so this is the same colour it always was, and #ffffff in
   dark instead of near-black on near-black (measured 1.02:1 -- invisible). */
.reg-games-h { font-size: 0.748rem; color: var(--text-strong, #111); }

/* TEN ROWS VISIBLE per section, scrollable. Derived from --side-row rather than a vh figure:
   70vh made the rail's height depend on the window instead of on the list, so the same page showed
   eleven consoles on a laptop and twenty-six on a monitor. --side-row is one .reg-con row
   (0.78rem type, 6px padding, 2px gap). */
.reg-side { --side-row: 31px; }
.reg-side-list { display: flex; flex-direction: column; gap: 2px; overflow-y: auto;
    max-height: calc(var(--side-row) * 10); padding-right: 4px; }
/* The SETS heading, when the rail carries a second section. Needs the air above it that the first
   heading gets from the page, or the two lists read as one. */
.reg-side-h2 { margin-top: 15px; }

/* ONE accent per column, used by the row name, its heading, the chevron and the press state. Green
   for consoles, blue for sets. On a phone both lists render as identical cards, so colour is the
   only thing left that tells you which list you are looking at -- that was the missing identity.
   Declared as a variable rather than repeated so the chevron and the :active border cannot end up
   a different green from the name, which is how the two drifted the first time. */
.reg-rail-con { --rail-accent: var(--green, #16a34a); --rail-press: #eef5ef; }
.reg-rail-set { --rail-accent: #2563eb; --rail-press: #eef2ff; }
.reg-rail a.reg-con .n { color: var(--rail-accent); font-weight: 700; }
.reg-rail .reg-side-h { color: var(--rail-accent); opacity: .9; }
/* --side-row is defined on .reg-side; the SETS column is not a .reg-side, so without this its
   .reg-side-list max-height calc() has no value to work with and silently does nothing. */
.reg-rail { --side-row: 31px; margin: 0 0 22px; }
.reg-con { display: flex; align-items: baseline; gap: 7px; padding: 6px 9px; border-radius: 6px;
    font-size: 0.78rem; text-decoration: none; border: 1px solid transparent; }
.reg-con .n { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; }
.reg-con .t { flex: 0 0 auto; font-size: 0.68rem; color: var(--text-muted, #8a97a6); }
/* LIVE: a real link. SOON: not a link at all, and it must not look like one -- a console nobody can
   open should not invite the click. */
a.reg-con { color: var(--text, #e6ebf0); border-color: rgba(127,127,127,.18); }
a.reg-con:hover { border-color: var(--neon-green, #4ade80); color: var(--neon-green, #4ade80); }
a.reg-con.on { border-color: var(--neon-green, #4ade80); background: rgba(74,222,128,.10);
    color: var(--neon-green, #4ade80); font-weight: 700; }
span.reg-con { color: var(--text-muted, #8a97a6); opacity: .62; cursor: default; }
/* A console with a full catalog and nothing owned yet. Still a link -- its board invites you to be the
   first name on it -- but it must not compete with the boards that have something on them. Dimmer than a
   normal row and brighter than the un-launched 'soon' spans, so the list reads as three states. */
a.reg-con-empty { opacity: .45; }
a.reg-con-empty:hover { opacity: 1; }
span.reg-con .soon { flex: 0 0 auto; font-size: 0.58rem; letter-spacing: .6px; text-transform: uppercase;
    border: 1px solid currentColor; border-radius: 3px; padding: 0 3px; opacity: .8; }
body.work-mode a.reg-con { color: #222; }
body.work-mode a.reg-con:hover { color: var(--green, #16a34a); border-color: var(--green, #16a34a); }
body.work-mode a.reg-con.on { color: var(--green, #16a34a); border-color: var(--green, #16a34a);
    background: rgba(22,163,74,.08); }

/* The OWNED bar sits beside the GRADED one and must not compete with it: same geometry, muted
   fill. Graded is the ranked number, owned is context, and if both bars were the same weight the
   longer one would read as the more important. */
/* RANK CELL on a game board: star for first, double star for a shared first, TIE chip on any shared
   rank. Laid out as a column so the chip sits under the number instead of widening a cell whose whole
   job is to be narrow. */
.reg-rank { white-space: nowrap; }
/* STAR then NUMBER, with the star in a RESERVED slot.
   Which side the star sat on was never the problem -- only row 1 has one, so with the star inline the
   digits sat at different x positions in either order. A fixed first column means a starless row still
   reserves the space and every digit starts at the same x. 22px fits the double star at 0.8rem, and the
   star is right-aligned in its slot so it hugs the number instead of floating off. */
.rg-rank-line { display: inline-grid; grid-template-columns: 22px auto; align-items: baseline;
    column-gap: 3px; }
/* CENTRED in the slot, not end-aligned. TIE sits under this in the same column and is centred, so
   end-aligning the stars put the two 5px out of line (measured: star centre 30px, TIE centre 25px).
   Both centred means the chip sits squarely under the star row. */
.rg-star { grid-column: 1; justify-self: center; color: #d8a21a; font-size: 0.8rem; line-height: 1;
    letter-spacing: -1px; }
.rg-star-tie { letter-spacing: -2px; }     /* two stars should read as a pair, not as two marks */
.rg-rank-n { grid-column: 2; justify-self: start; }
/* TIE lives in column 1, the star slot. The column is a fixed 22px so a wider chip overflows it
   visually without changing its width, which is what keeps every digit on its shared x.
   WHICH ROW depends on whether there is a star above it:
     rank 1 (.rg-top)  -> row 2, directly under the stars, which is what it qualifies
     any other rank    -> row 1, in the star slot itself, on the same line as the number. There is no
                          star on those rows, so the chip was otherwise hanging under an empty slot
                          with nothing to attach to. */
.rg-tielbl { grid-column: 1; justify-self: center; font-family: 'Oxanium', monospace; font-weight: 800;
    font-size: 0.5rem; letter-spacing: .8px; color: var(--text-muted, #8a97a6); }
.rg-top .rg-tielbl { grid-row: 2; }
.reg-rank:not(.rg-top) .rg-tielbl { grid-row: 1; align-self: center; }

/* ---- breadcrumb ------------------------------------------------------------------------
   ONE definition, used by the console board, the game board and the member page via
   _registry_crumb.html. Not on /registry itself -- that IS the root, and a trail with one entry
   pointing at the page you are on is noise.
   Was three separate implementations: .sc-crumb on the member page (Oxanium, green, with a back
   arrow AND the current page) and two different .reg-crumb rules on the boards (smaller, muted, and
   between them missing the current page, the game name and the arrow). This is the member page's
   version, one size up.
   display:flex with wrap so a long game title drops to a second line instead of overflowing. */
.reg-crumb { display: flex; flex-wrap: wrap; align-items: center; gap: 9px; margin: 16px 0 24px;
    font-family: 'Oxanium', monospace; font-weight: 700; font-size: 0.95rem;
    letter-spacing: 1px; text-transform: uppercase; line-height: 1.15; }
/* nowrap per SEGMENT. The crumb is a wrapping flex row, which is right -- a long game title should
   drop to a second line -- but without this the title split mid-word instead of moving as a unit,
   which is what looked broken. */
.reg-crumb a, .reg-crumb-here { white-space: nowrap; }
.reg-crumb a { color: var(--sc-accent, var(--green, #16a34a)); text-decoration: none; transition: color .15s ease; }
.reg-crumb a:hover { text-decoration: underline; }
.reg-crumb-sep { color: var(--text-muted, #8a97a6); opacity: .55; }
/* --sc-accent first: on a member page that is the colour THEY chose for their own page. Unset on the
   boards, so those fall through to ordinary text. */
.reg-crumb-here { color: var(--sc-accent, var(--text, #1a1a1a));
    max-width: 48vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 560px) {
    .reg-crumb { font-size: 0.82rem; gap: 7px; margin: 12px 0 18px; }
    .reg-crumb-here { max-width: 70vw; }
}

/* ---- headings / intro ------------------------------------------------------------------- */
.reg-h1 { font-family: 'Oxanium', monospace; font-weight: 800; letter-spacing: 2px; margin: 0 0 4px; }
.reg-sub { color: var(--text-muted, #8a97a6); font-size: 0.84rem; margin: 0 0 18px; line-height: 1.5; }
.reg-note { border-left: 2px solid var(--gold, #ffd166); background: rgba(255,209,102,.07);
    padding: 10px 12px; border-radius: 4px; font-size: 0.8rem; line-height: 1.55;
    color: var(--text-muted, #8a97a6); margin: 0 0 18px; }
.reg-note b { color: var(--gold, #ffd166); }
.reg-cta { display: flex; flex-wrap: wrap; gap: 9px; margin: 0 0 22px; }
.reg-cta a { font-family: 'Oxanium', monospace; font-weight: 700; letter-spacing: 1px;
    font-size: 0.74rem; text-decoration: none; padding: 9px 14px; border-radius: 7px;
    border: 1px solid var(--neon-green, #4ade80); color: var(--neon-green, #4ade80); }
.reg-cta a:hover { background: rgba(74,222,128,.12); }
.reg-cta a.ghost { border-color: rgba(127,127,127,.35); color: var(--text-muted, #8a97a6); }
/* The one thing a visitor can act on today, so it is filled rather than outlined -- there is nothing
   else on the page competing for the click. */
.reg-cta a.bright { background: var(--neon-green, #4ade80); color: #0b0b0b; border-color: transparent;
    box-shadow: 0 4px 16px -6px rgba(74,222,128,.7); }
.reg-cta a.bright:hover { filter: brightness(1.08); background: var(--neon-green, #4ade80); }
body.work-mode .reg-cta a.bright { background: var(--green, #16a34a); color: #fff;
    box-shadow: 0 4px 16px -6px rgba(22,163,74,.55); }
/* One statement per line. The page explains a three-column table, so it should read as three
   statements rather than as a paragraph that defines each term mid-sentence. */
.reg-lines { margin: 8px 0 0; }
.reg-lines p { margin: 0 0 11px; font-size: 0.84rem; line-height: 1.5;
    color: var(--text-muted, #8a97a6); }
.reg-lines p b, .reg-lines p strong { color: var(--text, #e6ebf0); }
body.work-mode .reg-lines p b, body.work-mode .reg-lines p strong { color: #222; }
body.work-mode .reg-cta a { border-color: var(--green, #16a34a); color: var(--green, #16a34a); }
body.work-mode .reg-cta a.ghost { border-color: rgba(0,0,0,.2); color: #555; }

/* ---- leaderboard ------------------------------------------------------------------------ */
.reg-board { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
.reg-board th { font-family: 'Oxanium', monospace; font-weight: 800; font-size: 0.64rem;
    letter-spacing: 1.2px; text-transform: uppercase; color: var(--text-muted, #8a97a6);
    text-align: right; padding: 0 9px 7px; border-bottom: 1px solid rgba(127,127,127,.25);
    white-space: nowrap; cursor: pointer; user-select: none; }
.reg-board th:first-child, .reg-board th.l { text-align: left; }
.reg-board th .ar { opacity: 0; font-size: 0.7em; }
.reg-board th.sorted .ar { opacity: 1; }
.reg-board td { padding: 8px 9px; text-align: right; border-bottom: 1px solid rgba(127,127,127,.10);
    white-space: nowrap; }
.reg-board td.l { text-align: left; }
.reg-board tbody tr:hover { background: rgba(127,127,127,.07); }
/* The whole row navigates (registry-rowlink.js), so it has to look like it does. :has() scopes this to
   rows that actually contain a link, so a future header or empty-state row does not claim to be
   clickable. Supported everywhere we target; without it the rule simply does not apply and the row is
   still clickable, just without the cue. */
.reg-board tbody tr:has(a[href]) { cursor: pointer; }
.reg-rank { font-family: 'Oxanium', monospace; font-weight: 800; color: var(--text-muted, #8a97a6);
    width: 1%; }
/* Gold is .rg-top ONLY -- an explicit "this row is first place" -- never "whatever row is first".
   The blanket tr:nth-child(1) rule that used to live here also golded row 1 of the set page's
   CHECKLIST, where 1 is a slot number in a list of 30 games and means nothing of the sort. Every
   board that wants it now says so: the game board, the set board and the console leaderboard all
   set .rg-top on rank 1. */
/* ...and on a GAME board first place can be SHARED, so gold has to follow the RANK rather than the row
   position. tr:nth-child(1) golds only the first <tr>, which left the second half of a tie for first in
   muted grey beside an identical gold 1. */
.reg-board .reg-rank.rg-top { color: var(--gold, #ffd166); }
/* The rank number and the handle have to sit on one line. Cells are vertical-align:top board-wide and
   .reg-who is a centred flex row whose height the avatar sets, so a top-aligned rank drifted off it. */
/* LEFT, not the board's inherited right. The grid is an inline-grid, so right-aligning it meant its
   whole width was pushed against the cell's right edge -- and the TIE rows have a wider second column
   than the bare-number rows, so their digits landed 8px further left (measured 39px vs 47px). Aligned
   left, the grid starts at the same x on every row and the fixed star column puts every digit at the
   same offset from it. */
/* RANK CELLS on every board: the leaderboard, the most-owned games table, and a game's owners.
   LEFT, not the board's inherited right -- right-aligning makes a 1 and a 10 END at the same x and START
   at different ones, so the numbers appear to drift against the names beside them.
   MIDDLE, because cells are vertical-align:top board-wide while .reg-who and .reg-game are centred flex
   rows whose height an avatar or cover sets, so a top-aligned rank sat above the name it labels. */
.reg-board .reg-rank { vertical-align: middle; text-align: left; }
.reg-board th:first-child { text-align: left; }
.reg-who { display: flex; align-items: center; gap: 8px; text-decoration: none;
    color: var(--text, #e6ebf0); font-weight: 600; }
.reg-who:hover { color: var(--neon-green, #4ade80); }
body.work-mode .reg-who { color: #222; }
body.work-mode .reg-who:hover { color: var(--green, #16a34a); }
.reg-who img { width: 24px; height: 24px; border-radius: 50%; flex: 0 0 auto; }
.reg-bar { position: relative; height: 5px; border-radius: 3px; background: rgba(127,127,127,.18);
    min-width: 54px; margin-top: 4px; overflow: hidden; }
.reg-bar i { position: absolute; inset: 0 auto 0 0; background: var(--neon-green, #4ade80);
    border-radius: 3px; }
body.work-mode .reg-bar i { background: var(--green, #16a34a); }
/* OWNED is deliberately the only UNCOLOURED bar: green is reserved for the measurement that ranks
   you. This was blue (#5b9bd5), which was right while the goal was "keep both bars readable" -- but
   two fully saturated bars read as parallel and EQUAL, and OWNED never earns a rank. Grey is the
   message, not a leftover: not disabled, not scored. It stays clearly lighter than the .18 track
   above so it still reads as a filled bar rather than an empty one.
   MUST sit after the .reg-bar rules above -- same specificity (0,2,2), so whichever comes last wins,
   and this was previously declared earlier in the file and silently lost. */
.reg-bar-owned i { background: rgba(165,175,170,.55); }
body.work-mode .reg-bar-owned i { background: rgba(85,95,90,.42); }
.reg-num { font-family: 'Share Tech Mono', monospace; }
/* The SAME mono as .reg-num -- it only differs in colour. It set a colour and no font-family, so it
   inherited Open Sans and "42/318" rendered as two typefaces pretending to be one number. */
.reg-dash { color: var(--text-muted, #8a97a6); font-family: 'Share Tech Mono', monospace; }

/* TOP, not middle. Only OWNED and GRADED carry a bar, so those cells are two lines tall while
   COMPLETE / AVG GRADE / RATING are one. vertical-align:middle centred each cell independently, so no
   two numbers in a row shared a baseline -- that was the "shifting", and it was the text moving, not
   the bars. Top-aligning puts every first line on one baseline and lets the bars hang beneath. */
.reg-board td { vertical-align: top; }
/* ...and the one-line cells need the same optical start as the stacked ones. */
.reg-board td.l { vertical-align: top; }

/* Number and bar as ONE unit, sized to the bar. The bar was a full-width block under a right-aligned
   number, so the number's left edge drifted with its digit count while the bar stayed put. Wrapping
   them makes the pair move together and keeps the fraction sitting directly over its own bar. */
/* vertical-align:top is load-bearing. An inline-block baseline-aligns off its LAST line box, which
   here is the BAR -- so the number sat 10px below the plain text in the cells beside it (measured:
   344px against 334px). Aligning the box's TOP instead puts the fraction on the same line as every
   other number in the row, which is the whole point of the wrapper. */
.reg-stack { display: inline-block; min-width: 72px; text-align: right; vertical-align: top; }
.reg-empty { color: var(--text-muted, #8a97a6); font-size: 0.84rem; padding: 26px 2px;
    line-height: 1.6; }

/* HIDDEN, NOT DELETED. The rating still ranks this board -- the server sorts by it and # is that
   rank -- and data-rating is still on every row, so the sorter and any future reveal are intact.
   Base section on purpose: inside the 760px query this would just repeat .opt. */
.reg-board .reg-off { display: none; }

/* A phone has no room for a 208px rail beside a 6-column table: the sidebar becomes a scrolling
   strip above the board, and the two softest columns are dropped rather than squeezed. */
@media (max-width: 760px) {
    .reg-wrap { grid-template-columns: 1fr; gap: 14px; }
    .reg-side { position: static; }
    /* MOBILE: the console rail exists only on /registry, where the list IS the page's content.
       On a console or game board it is gone entirely -- no rail and no dropdown. The breadcrumb above
       already goes back to the console and to the registry, so a jump-list there is a third nav
       control leading somewhere you did not come from, and the heading over a hidden list was worse.
       .reg-side-root is set by _registry_side.html when no console is open. */
    .reg-side { display: none; }
    .reg-side.reg-side-root { display: block; }
    .reg-side.reg-side-root .reg-side-list { display: flex; max-height: none; overflow-y: visible; }
    /* A GAME page drops the console picker on mobile altogether. The breadcrumb above it already goes
       back to the console AND to the registry, so a console jump-list is a third nav control leading
       somewhere you did not come from. The console board keeps its picker -- there the other consoles
       are siblings of what you are looking at, not a detour. Desktop keeps the rail on both, where it
       is a sidebar and costs nothing. */

    /* The mobile list has to LOOK tappable. It had none of the usual signals -- 6px of padding, no
       surface, body-text colour, nothing on the right edge -- so it read as text to scan rather than
       rows to press. */
    .reg-rail .reg-side-list { gap: 7px; }
    .reg-rail .reg-con {
        align-items: center;            /* baseline alignment is for a dense rail, not a 48px row */
        /* border-box is load-bearing: with the default content-box, min-height:48px meant 48px of
           CONTENT plus 24px padding plus 2px border = a 74px row (measured). 48px is meant to be the
           whole tap target, not the text box inside it. */
        box-sizing: border-box;
        min-height: 48px;               /* the usual floor for a thumb target */
        padding: 12px 13px;
        border-radius: 10px;
        /* --surface IS #ffffff in light -- identical to the #fff this replaces -- and a dark
           card in dark mode. Hardcoded white was why the rail rendered as white cards with
           green text at 1.74:1 for a dark-theme user on a phone. The border stays a literal:
           --border is #e5e7eb in light, which would NOT match, and a faint border on a dark
           card costs nothing. */
        background: var(--surface, #fff);
        border: 1px solid rgba(0,0,0,.10);
        box-shadow: 0 1px 1px rgba(0,0,0,.03);
    }
    /* the name in the link green -- the colour everything else clickable on the site uses */
    .reg-rail a.reg-con .n { font-size: 0.95rem; font-weight: 700; }
    .reg-rail .reg-con .t { font-size: 0.74rem; }
    /* A chevron, from CSS so the markup does not change. ONLY on <a>: an arrow on a console that does
       not navigate yet (the "soon" <span>) is a worse lie than no arrow at all. */
    .reg-rail a.reg-con::after {
        content: '\203A'; flex: 0 0 auto; margin-left: 2px;
        font-family: 'Oxanium', monospace; font-size: 1.15rem; line-height: 1;
        color: var(--rail-accent, #16a34a); opacity: .55;
    }
    /* press feedback: a card that does not react to a touch feels broken even when it worked */
    .reg-rail a.reg-con:active { background: var(--rail-press, #eef5ef);
        border-color: var(--rail-accent, #16a34a); }
    /* no catalog yet -> not a link, so it must not look like one */
    .reg-rail span.reg-con { background: transparent; border-style: dashed; opacity: .75; }
    /* a full catalog with nothing owned IS still worth opening -- dimmed, but a full-size row */
    .reg-rail a.reg-con.reg-con-empty .n { opacity: .72; font-weight: 600; }
    /* the rail's 70vh cap exists so a STICKY desktop sidebar cannot outrun the viewport; on a phone,
       where this list is the page, it became a short scrolling window inside a scrolling page. */
    .reg-cta { justify-content: center; }
    /* Tables: drop the soft columns, shrink the type, and let the NAME columns WRAP instead of
       forcing the row wider than the screen (that h-scroll was zooming the whole page out). */
    .reg-board .opt { display: none; }
    .reg-board.reg-games .opt { display: table-cell; }   /* games table shows OWNERS + COPIES on mobile */
    .reg-board { font-size: 0.66rem; }
    .reg-board th { font-size: 0.5rem; letter-spacing: .2px; }
    .reg-board td, .reg-board th { padding: 6px 4px; }
    .reg-board td.l, .reg-board th.l { white-space: normal; word-break: break-word; }
    .reg-num { font-size: 0.66rem; }                        /* data columns compact */
    .reg-who, .reg-game { font-size: 0.82rem; }
    .reg-games .reg-game { font-size: 0.76rem; }   /* room for the extra column; title still wraps */             /* username + game title stay readable */
    /* The bars STAY on the leaderboard: OWNED against GRADED is the comparison this board exists
       to make, and in narrow columns the eye reads two bar lengths faster than two fractions. Only
       the games table drops them, where a bar carries no comparison. */
    .reg-board.reg-games .reg-bar { display: none; }
    .reg-board .reg-bar { height: 4px; }       /* slimmer, so two bars still fit the row */
    .reg-who { gap: 6px; }
    .reg-who img { width: 20px; height: 20px; }
    .reg-game { gap: 8px; }
    .reg-h1 { letter-spacing: 1px; }
}

/* ---- games table (the game-registry list under a console board) ------------------------- */
.reg-game { display: flex; align-items: center; gap: 10px; text-decoration: none;
    color: var(--text, #e6ebf0); font-weight: 600; }
.reg-game:hover { color: var(--neon-green, #4ade80); }
body.work-mode .reg-game { color: #222; }
body.work-mode .reg-game:hover { color: var(--green, #16a34a); }
.reg-game img { width: 32px; height: auto; object-fit: cover; border-radius: 3px; flex: 0 0 auto;
    background: rgba(127,127,127,.15); }

/* ---- per-game registry header ----------------------------------------------------------- */
.reg-gamehd { display: flex; align-items: center; gap: 16px; margin: 0 0 18px; }
.reg-gamecover { width: 66px; height: auto; object-fit: cover; border-radius: 5px; flex: 0 0 auto;
    background: rgba(127,127,127,.15); box-shadow: 0 3px 12px -5px rgba(0,0,0,.5); }
.reg-gamehd .reg-h1 { margin: 0 0 3px; }
/* The pop-report link beside the game title. Sized off the h1 (em, not rem) so it tracks the clamped
   title at every width, and baseline-ish rather than centred so it sits with the text and not with the
   title's full line box. */
.reg-popbtn { display: inline-block; margin-left: 8px; font-size: 0.62em; vertical-align: 2px;
    color: var(--green, #16a34a); text-decoration: none; opacity: .75; transition: opacity .15s ease; }
.reg-popbtn:hover { opacity: 1; }

/* ---- pager (shared: leaders, games, game owners) ---------------------------------------- */
.reg-pager { display: flex; align-items: center; justify-content: center; gap: 16px; margin: 14px 0 2px; }
.reg-pager:empty { display: none; }
.rp-b { font-family: 'Oxanium', monospace; font-weight: 800; font-size: .95rem; line-height: 1;
    cursor: pointer; color: var(--text, #e6ebf0); background: transparent;
    border: 1px solid rgba(127,127,127,.3); border-radius: 6px; padding: 6px 13px; }
.rp-b:hover:not([disabled]) { border-color: var(--neon-green, #4ade80); color: var(--neon-green, #4ade80); }
.rp-b[disabled] { opacity: .32; cursor: default; }
.rp-n { font-family: 'Share Tech Mono', monospace; font-size: .74rem; color: var(--text-muted, #8a97a6); }
body.work-mode .rp-b { color: #222; }
body.work-mode .rp-b:hover:not([disabled]) { border-color: var(--green, #16a34a); color: var(--green, #16a34a); }

@media (max-width: 760px) {
    .reg-game img { width: 28px; height: auto; }
    .reg-gamecover { width: 54px; height: auto; }
    .reg-gamehd { gap: 12px; }
}

/* ---- mobile framework: let grid children shrink, let a too-wide table scroll inside its
   own box instead of widening (and clipping) the whole page. Same pattern as aplusplus/admin. */
.reg-wrap > * { min-width: 0; }
.reg-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* console dropdown -- desktop hidden, shown on mobile in place of the rail */
.reg-side-select { display: none; width: 100%; padding: 9px 11px; border-radius: 7px;
    border: 1px solid rgba(127,127,127,.3); background: transparent; color: var(--text, #e6ebf0);
    font-family: 'Oxanium', monospace; font-weight: 700; font-size: 0.82rem; letter-spacing: .5px; }
body.work-mode .reg-side-select { color: #222; background: #fff; }

/* The CONSOLES / SETS label above a list -- a prompt, so it gets the weight and the accent.
   Scoped to .reg-rail, not .reg-side: scoped to the aside, CONSOLES got 0.84rem and SETS, which
   lives in <main> on the landing page, fell back to the 0.68rem base and read as a smaller
   heading for no reason. The colour comes from --rail-accent (see the accents block), so this
   rule no longer sets one -- it was hardcoding green onto a heading that is blue for sets. */
.reg-rail .reg-side-h { font-size: 0.84rem; font-weight: 800; letter-spacing: 1.6px; }

/* game-registry member cell: handle on top, a clear 'N copies' sub-line (NOT N-at-this-grade) */
/* ROW, not column. As a flex column the copy count sat on a second line and any member with
   duplicates got a double-height row. baseline so the badge sits on the handle's baseline rather than
   floating against the top of the box. */
.rg-who-col { display: flex; flex-direction: row; align-items: baseline; gap: 6px; min-width: 0; }
/* the handle is what gives when the column is tight -- the badge is 3 characters and must not ellipsis */
.rg-handle { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rg-copies { flex: 0 0 auto; font-size: 0.68rem; font-weight: 700; letter-spacing: .3px;
    color: var(--text-muted, #8a97a6); border: 1px solid rgba(127,127,127,.30);
    border-radius: 4px; padding: 0 4px; line-height: 1.5; }

/* ---- game board: the VARIANT cell -------------------------------------------------------
   One row per owner per variant, with the printing named in its own cell: `PSA  Made in USA,
   Rockstar Security Label`. This replaced a section heading per variant, which was three lines of
   chrome around a single row -- 745 of the 864 owned variants on this registry have exactly one
   owner.
   The badge is the grader whose CATALOGUE the variant comes from, and it carries real information:
   six games own two variants of the same printing catalogued by both PSA and CGC, identical name,
   and the badge is all that separates the rows. Same chip shape as .rg-copies so the two read as
   one family.
   baseline alignment so the badge sits on the name's baseline instead of its border-box shoving the
   name up; the name wraps rather than widening a table on a page that sets overflow-x: hidden and
   would simply clip it. */
.rg-var { max-width: 300px; }
/* DESKTOP TYPE, a notch down, and only on the game-owners board: six columns with a free-text one
   among them, where every other registry table is five of short values. Inside a min-width query
   rather than left to specificity -- #gameOwners is (1,0,0) and would beat the (0,1,0) .reg-board
   rule in the mobile block below regardless of source order, shrinking the phone layout with it. */
@media (min-width: 769px) {
    #gameOwners { font-size: 0.74rem; }
    #gameOwners th { font-size: 0.58rem; }
    #gameOwners td { padding: 7px 8px; }
}
.rg-vsrc { display: inline-block; font-family: 'Oxanium', monospace; font-weight: 800;
    font-size: 0.55rem; letter-spacing: .6px; color: var(--text-muted, #8a97a6);
    border: 1px solid rgba(127,127,127,.34); border-radius: 4px; padding: 1px 4px;
    line-height: 1.4; margin-right: 5px; vertical-align: 1px; }
.rg-vname { color: var(--text-muted, #8a97a6); }
.rg-vname[title] { border-bottom: 1px dotted rgba(127,127,127,.35); cursor: help; }
@media (max-width: 768px) {
    .rg-var { max-width: 150px; }
    .rg-vsrc { font-size: 0.48rem; margin-right: 3px; }
}

/* ---- Top of Pop (registry homepage): a ranked member list, each row expands to its games ---- */
.tp-h { font-size: 0.84rem; }
.tp-sub { margin: 4px 0 12px; }
.tp-list { display: flex; flex-direction: column; gap: 6px; }
.tp-item { border: 1px solid rgba(127,127,127,.18); border-radius: 8px; overflow: hidden; }
.tp-row { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; font-family: inherit;
    background: transparent; border: 0; padding: 10px 12px; cursor: pointer; color: var(--text, #e6ebf0); }
.tp-row:hover { background: rgba(127,127,127,.07); }
.tp-rank { font-family: 'Oxanium', monospace; font-weight: 800; color: var(--text-muted, #8a97a6); min-width: 1.4em; text-align: right; }
.tp-item:nth-child(1) .tp-rank { color: var(--gold, #ffd166); }
.tp-who { font-weight: 700; color: var(--text, #e6ebf0); text-decoration: none; }
.tp-who:hover { color: var(--neon-green, #4ade80); text-decoration: underline; }
body.work-mode .tp-who { color: #222; }
body.work-mode .tp-who:hover { color: var(--green, #16a34a); }
.tp-stat { margin-left: auto; font-size: 0.8rem; color: var(--text-muted, #8a97a6); white-space: nowrap; }
.tp-stat b { color: var(--gold, #ffd166); }
.tp-caret { color: var(--text-muted, #8a97a6); transition: transform .15s ease; flex: 0 0 auto; }
.tp-item.open .tp-caret { transform: rotate(180deg); }
.tp-games { display: none; border-top: 1px solid rgba(127,127,127,.14); }
.tp-item.open .tp-games { display: block; }
.tp-game { display: flex; align-items: center; gap: 9px; padding: 7px 12px 7px 36px; text-decoration: none;
    color: var(--text, #e6ebf0); font-size: 0.84rem; border-top: 1px solid rgba(127,127,127,.07); }
.tp-game:first-child { border-top: 0; }
.tp-game:hover { background: rgba(127,127,127,.06); color: var(--neon-green, #4ade80); }
body.work-mode .tp-game { color: #333; }
body.work-mode .tp-game:hover { color: var(--green, #16a34a); }
.tp-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tp-con { flex: 0 0 auto; font-size: 0.66rem; text-transform: uppercase; letter-spacing: .5px; color: var(--text-muted, #8a97a6); }
.tp-grade { flex: 0 0 auto; font-family: 'Share Tech Mono', monospace; color: var(--text-muted, #8a97a6); }
.tp-pop { flex: 0 0 auto; font-family: 'Oxanium', monospace; font-weight: 700; font-size: 0.62rem; letter-spacing: .5px;
    padding: 2px 7px; border-radius: 999px; border: 1px solid rgba(127,127,127,.3); color: var(--text-muted, #8a97a6); white-space: nowrap; }
.tp-pop.sole { color: var(--gold, #ffd166); border-color: rgba(255,209,102,.5); background: rgba(255,209,102,.08); }
@media (max-width: 760px) {
    .tp-stat { font-size: 0.72rem; }
    .tp-game { padding-left: 22px; font-size: 0.78rem; gap: 6px; }
    .tp-con { display: none; }
}

.tp-more { padding: 7px 12px 9px 36px; font-size: 0.74rem; color: var(--text-muted, #8a97a6); font-style: italic; }

.tp-vchk { color: var(--neon-green, #4ade80); font-size: 0.82em; }
body.work-mode .tp-vchk { color: var(--green, #16a34a); }
.tp-vok { color: var(--neon-green, #4ade80); font-weight: 700; }
body.work-mode .tp-vok { color: var(--green, #16a34a); }


/* ---- /registry three-column landing: CONSOLES | SETS | empty -------------------------------
   The console column is the existing .reg-side rail (grid column 1 of .reg-wrap). Declaring a
   third column with nothing to put in it is what leaves the empty slot -- cheaper and less to
   keep in sync than an empty <div> with its own class.
   --rp-row is the height of ONE row, and every 5-rows-visible cap is calc()'d from it, so the cap
   stays 5 rows after a type or padding change instead of silently showing 4.5. */
.reg-home3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* DESKTOP IS FULL LENGTH. Both lists run to their natural height and the PAGE scrolls; the rail's
   own 70vh cap is lifted here too, since a capped rail beside an uncapped SETS box is the one
   combination that looks like a mistake. Only the phone caps them -- see the media query. */
.reg-home3 .reg-side-list { max-height: none; overflow-y: visible; }

/* Both landing columns are the rail component (.reg-side-list > a.reg-con), so there are no row
   styles here. The .reg-pickrow / .rp-name / .rp-meta block that used to live here was a second
   implementation of a rail row, and it drifted: on a phone the real rail grew 48px cards, a
   chevron and a press state while this one stayed 6px of text. Deleted rather than re-synced. */

/* The set board uses the console board's .reg-stack / .reg-bar cells, so it has no styles of its
   own. The .rg-comp* block that lived here styled a COMPLETION column that OWNED replaced. */
@media (max-width: 768px) {
    /* ONE column, consoles over sets, five rows each. The root rail renders as big tap targets
       here (0.95rem, 7px gaps), so its row is taller than the desktop one -- hence its own
       --rp-row rather than reusing the desktop figure and capping at four and a half rows. */
    .reg-home3 { grid-template-columns: 1fr; }

    /* Both landing columns: five cards visible, then scroll. ONE selector, because consoles and
       sets are the same component now.
       The gradient fade this block used to carry is GONE. It was painted on the scroll container,
       behind rows that each have their own opaque --surface background, so it never read as a
       fade -- only as a smear in the 7px gaps between cards. A border, a drawn scrollbar in the
       column's own accent, and the indent below say "this scrolls" without it. */
    .reg-home3 .reg-rail .reg-side-list {
        --rp-row: 55px;                  /* a 48px card plus the 7px gap under it */
        max-height: calc(var(--rp-row) * 5);
        overflow-y: auto;
        /* INSET past its own heading, so the heading reads as a label ON the box instead of as
           the first thing inside it. BOTH sides: margin-left alone left the box flush with the
           page gutter on the right and 10px off it on the left, which read as the whole list
           being shifted rather than as an indent. */
        margin-left: 10px; margin-right: 10px;
        padding: 6px;
        border: 1px solid rgba(127,127,127,.28); border-radius: 10px;
        scrollbar-width: thin; scrollbar-color: var(--rail-accent, #888) transparent; }
    .reg-home3 .reg-rail .reg-side-h { margin-bottom: 6px; }
    .reg-home3 .reg-rail .reg-side-list::-webkit-scrollbar { width: 8px; }
    .reg-home3 .reg-rail .reg-side-list::-webkit-scrollbar-track {
        background: rgba(127,127,127,.10); border-radius: 4px; }
    .reg-home3 .reg-rail .reg-side-list::-webkit-scrollbar-thumb {
        background: var(--rail-accent, #888); border-radius: 4px; }

}

/* The actual box title, under a set row whose label differs from it. A second line rather than a
   parenthetical on the first: the label is what you scan the checklist for, the box title is what
   you check against the shelf. */
.rg-boxtitle { display: block; font-size: 0.66rem; color: var(--text-muted, #8a97a6);
    font-style: italic; margin-top: 1px; }

/* The game count on a set page carries the set's rule in its tooltip, so it gets the same dotted
   underline the variant names use to say "there is more here" rather than being a silent hover. */
.rg-ruletip { border-bottom: 1px dotted rgba(127,127,127,.45); cursor: help; }

/* ---- set board: the expandable member row -------------------------------------------------
   The caret is on the rank cell rather than a column of its own: the board is five columns of
   numbers already, and a sixth holding one glyph would push the type down on a phone. */
table[data-expand] tbody tr:not([data-detail]) { cursor: pointer; }
table[data-expand] tbody tr:not([data-detail]):hover { background: rgba(127,127,127,.07); }
table[data-expand] tbody tr:not([data-detail]) .reg-rank::after {
    content: '\203A'; margin-left: 5px; color: var(--text-muted, #8a97a6);
    display: inline-block; transition: transform .12s ease; }
table[data-expand] tbody tr.open .reg-rank::after { transform: rotate(90deg); }
table[data-expand] tbody tr:focus-visible { outline: 2px solid var(--green, #16a34a);
    outline-offset: -2px; }

.rg-det { background: rgba(127,127,127,.06); padding: 10px 12px 12px !important; }
.rg-det-h { font-family: 'Oxanium', monospace; font-weight: 800; font-size: 0.62rem;
    letter-spacing: 1px; color: var(--text-muted, #8a97a6); padding-bottom: 7px; }
.rg-det-game { font-size: 0.78rem; text-decoration: none; color: var(--text, #e6ebf0); }
.rg-det-game:hover { text-decoration: underline; }
body.work-mode .rg-det-game { color: #222; }
.rg-det-grade { font-family: 'Oxanium', monospace; font-weight: 700; font-size: 0.72rem;
    white-space: nowrap; }
.rg-det-seal { color: var(--text-muted, #8a97a6); font-weight: 600; }


/* ---- set board + its expanded panel -------------------------------------------------------- */
/* Five columns fit a phone, so the owners board must not be a sideways scroller. .reg-scroll is
   shared and right for the boards that DO overflow (a free-text column), so this opts out rather
   than changing it. */
@media (max-width: 760px) {
    .reg-noscroll-m { overflow-x: visible; }
    /* what made it overflow: a 72px stack and a 54px bar in each of two count columns */
    #setOwners .reg-stack { min-width: 44px; }
    #setOwners .reg-bar { min-width: 34px; }
    #setOwners td, #setOwners th { padding: 6px 3px; }
}

/* The panel is a real table now: three unlabelled values per line read as a sentence, and COPIES
   especially -- a bare "3" beside a grade looks like part of the grade. */
.rg-det-t { width: 100%; border-collapse: collapse; }
.rg-det-t th { font-family: 'Oxanium', monospace; font-weight: 800; font-size: 0.55rem;
    letter-spacing: 1px; color: var(--text-muted, #8a97a6); text-align: right;
    padding: 0 0 5px; border-bottom: 1px solid rgba(127,127,127,.2); }
.rg-det-t th.l, .rg-det-t td.l { text-align: left; }
.rg-det-t td { padding: 4px 0; border-bottom: 1px solid rgba(127,127,127,.1);
    text-align: right; vertical-align: baseline; }
.rg-det-t tr:last-child td { border-bottom: 0; }
.rg-det-t td.l { max-width: 0; width: 99%; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; }
.rg-det-n { font-family: 'Share Tech Mono', monospace; font-size: 0.74rem;
    color: var(--text-muted, #8a97a6); white-space: nowrap; padding-right: 10px !important; }

/* ---- the set checklist: numbers hug their digits, the title takes the rest and wraps ---------
   .reg-board td is white-space:nowrap and the table is auto-layout, so the GAME column was sized
   by its longest row and the three short columns split whatever was left -- which is why #,
   CONSOLE and OWNERS sat far from their own headings with a lake of space around them.
   width:1% on a short column is the auto-layout shrink-to-content idiom: the browser cannot honour
   1% without clipping the content, so it falls back to the content width. The title then gets
   everything else, and it is the one cell allowed to wrap.
   Numbers stay nowrap so a count can never break across two lines. */
#setGames th:first-child, #setGames td:first-child,          /* # */
#setGames th:nth-child(3), #setGames td:nth-child(3),        /* CONSOLE */
#setGames th:last-child,  #setGames td:last-child {          /* OWNERS */
    width: 1%; white-space: nowrap; }
#setGames th:nth-child(2), #setGames td:nth-child(2) {        /* GAME */
    width: auto; white-space: normal; word-break: break-word; }
/* .reg-who is a flex row; without wrap the title and its "(= Final Fantasy IV)" parenthetical are
   one unbreakable line however wide the cell is. */
#setGames .reg-who { flex-wrap: wrap; align-items: baseline; }

/* VIEW PROFILE, inside the panel. The row itself no longer navigates, so this is the only route to
   a member page from a board -- it has to be obvious rather than a courtesy. */
.rg-det-prof { display: inline-block; margin: 0 0 9px; text-decoration: none;
    font-family: 'Oxanium', monospace; font-weight: 800; font-size: 0.58rem; letter-spacing: 1px;
    color: var(--green, #16a34a); }
.rg-det-prof:hover { text-decoration: underline; }
/* the panel is two columns now; GAME takes the room COPIES used to */
.rg-det-t .rg-copies { margin-left: 6px; }
