/* dubTC web-tools design system — the shared look for every dub.tc tool.
   Direction (Luke 2026-07-13): neon-green tinted translucent glass pane on a
   soft off-white background, black text, Roboto, no emoji, exactly two button
   schemes (normal + red). Every tool page links this file; restyling the whole
   suite is a one-file change here. Bump the ?v= query when it changes. */

@import url('https://fonts.googleapis.com/css2?family=Rajdhani:wght@600;700&family=Roboto:wght@400;500;700&display=swap');

:root {
  /* LIGHT (default): NEUTRAL surfaces — no green shading (Luke 2026-07-16).
     Green survives only as small accents: the active-tab underline, focus
     borders (--neon) and on-state chips. */
  --bg:        #e6e7e9;   /* flat neutral gray (background test) */
  /* HIGH CONTRAST IS THE HOUSE LOOK (Luke 2026-08-11: "remove the high
     contrast button and make the high contrast layouts the version we
     use"). --ring / --line / --ink-soft below carry what the old
     high-contrast override used to layer on top; there is no toggle. */
  --ink:       #0b0f0c;   /* black text */
  --ink-soft:  #3a4040;   /* secondary text (neutral, high-contrast) */
  --neon:      #00e676;   /* green ACCENT only — not surface shading */
  --line:      rgba(20,26,23,.38);   /* divider / hairline (neutral) */
  --pane-hdr:  rgba(0,0,0,.05);      /* header tint (neutral) */
  --pane-body: rgba(20,26,23,.06);   /* expanded-body fill — slightly darker than base */
  --ring:      rgba(20,26,23,.6);    /* borders (neutral) */
  --chip:      rgba(20,26,23,.06);
  --chip-ink:  #5a6060;
  --chip-on:   rgba(0,200,102,.18);  /* on-state accent stays green */
  --chip-on-ink:#0a6b3c;
  --red:       #c0342a;
  --red-fill:  rgba(214,58,46,.10);
  --red-ring:  rgba(214,58,46,.45);
  --radius:    2px;       /* squared edges */
  /* Themable surfaces — every gradient/fill/shadow the components use lives
     here so the [data-theme] blocks below can restyle the whole suite. */
  --pane-grad:   linear-gradient(135deg, rgba(255,255,255,.72), rgba(250,250,251,.5) 42%, rgba(244,245,246,.6));
  --pane-shadow: inset 0 1px 0 rgba(255,255,255,.75), 0 14px 44px rgba(25,30,28,.12);
  --head-grad:   linear-gradient(180deg, rgba(0,0,0,.06), rgba(0,0,0,.02));
  --head-grad-soft: linear-gradient(180deg, rgba(0,0,0,.05), rgba(0,0,0,.015));
  --btn-grad:    linear-gradient(180deg, rgba(255,255,255,.95), rgba(243,244,245,.85));
  --btn-hl:      inset 0 1px 0 rgba(255,255,255,.85);
  --btn-red-grad:linear-gradient(180deg, rgba(255,236,234,.95), rgba(250,220,217,.82));
  --field-bg:    rgba(255,255,255,.78);
  --surface:     rgba(255,255,255,.55);   /* generic card fill */
  --surface-soft:rgba(255,255,255,.45);
  --seg-bg:      rgba(255,255,255,.65);
  --toast-bg:    rgba(255,255,255,.96);
  --dlg-grad:    linear-gradient(135deg, rgba(255,255,255,.97), rgba(248,249,250,.95) 45%, rgba(242,243,244,.96));
  --dlg-shadow:  0 18px 60px rgba(25,30,28,.28);
  --inset-body:  inset 0 2px 7px rgba(25,30,28,.07);
  --hover:       rgba(20,26,23,.05);
  /* Native <option> lists are painted by the OS, not by the page. They take
     the select's own background-color/color and IGNORE rgba translucency —
     --field-bg is translucent everywhere and NEARLY TRANSPARENT in dark and
     dubtc, so options were rendering light ink on the OS's white popup:
     unreadable in every theme (Luke 2026-08-12). Options get an OPAQUE pair. */
  --opt-bg:      #ffffff;
  --opt-ink:     #0b0f0c;
  /* In-page scrollbars. The WINDOW's bar stays native (Luke: "the side scroll
     bar is fine"); everything that scrolls inside the page gets these. */
  --sb-thumb:    rgba(20,26,23,.28);
  --sb-thumb-hi: rgba(20,26,23,.48);
  /* Texture pass (Luke 2026-08-15, from the first UI demo, kept SUBTLE):
     a whisper of grain over every surface, pinstripes on panel headers,
     and a bottom lip that makes buttons read imprinted. Trim accent per
     skin: light = red, dark = blue, dubTC keeps its green. */
  --neon:       #b8352b;                 /* light-mode trim = red */
  --grain-op:   .028;
  --stripe:     rgba(20,26,23,.032);
  --btn-press:  inset 0 -1.5px 0 rgba(25,30,28,.12);
  /* Sub-header layer (Luke 2026-08-16): the title row of an item box sits on
     a SLIGHTLY different ground than its content — a quiet tint, no pattern
     (the stripe stays a page-hero device). */
  --subhead-bg: rgba(20,26,23,.045);
}

/* ---- DARK: shale — neutral slate grays, NO green cast (Luke 2026-07-19).
   The brand green lives in the dubTC skin; dark mode stays quiet. ---- */
html[data-theme="dark"] {
  --bg:        #15171a;
  /* Ink was softened off near-white for second-monitor comfort (Luke
     2026-07-19), then lifted to the former high-contrast values on
     2026-08-11 when high contrast became the house look (see :root). --ink
     stays one clear step ABOVE --ink-soft so labels/headers/muted text
     still read as secondary; matching them would flatten the hierarchy. */
  --ink:       #dfe5ea;
  --ink-soft:  #c2cad2;
  --line:      rgba(255,255,255,.3);
  --pane-body: rgba(0,0,0,.26);
  --ring:      rgba(255,255,255,.5);
  --chip:      rgba(255,255,255,.08);
  --chip-ink:  #9aa3ac;
  --chip-on:   rgba(148,163,184,.28);
  --chip-on-ink:#d3dbe3;
  --red:       #ff8177;
  --red-fill:  rgba(214,58,46,.16);
  --red-ring:  rgba(214,58,46,.55);
  --pane-grad:   linear-gradient(135deg, rgba(38,41,45,.94), rgba(28,31,35,.90) 42%, rgba(31,34,38,.94));
  --pane-shadow: inset 0 1px 0 rgba(255,255,255,.05), 0 14px 44px rgba(0,0,0,.55);
  --head-grad:   linear-gradient(180deg, rgba(255,255,255,.07), rgba(255,255,255,.015));
  --head-grad-soft: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.012));
  --btn-grad:    linear-gradient(180deg, rgba(62,66,72,.92), rgba(46,50,55,.88));
  --btn-hl:      inset 0 1px 0 rgba(255,255,255,.07);
  --btn-red-grad:linear-gradient(180deg, rgba(96,36,31,.92), rgba(72,27,23,.88));
  --field-bg:    rgba(255,255,255,.07);
  --surface:     rgba(255,255,255,.05);
  --surface-soft:rgba(255,255,255,.04);
  --seg-bg:      rgba(255,255,255,.07);
  --toast-bg:    rgba(33,36,40,.97);
  --dlg-grad:    linear-gradient(135deg, rgba(36,39,43,.98), rgba(27,30,34,.97));
  --dlg-shadow:  0 18px 60px rgba(0,0,0,.65);
  --inset-body:  inset 0 2px 7px rgba(0,0,0,.4);
  --hover:       rgba(255,255,255,.06);
  --opt-bg:      #22262b;   /* opaque — see the :root note */
  --opt-ink:     #dfe5ea;
  --sb-thumb:    rgba(255,255,255,.24);
  --sb-thumb-hi: rgba(255,255,255,.42);
  --neon:       #5b8fe8;                 /* dark-mode trim = blue */
  --grain-op:   .04;
  --stripe:     rgba(255,255,255,.028);
  --btn-press:  inset 0 -1.5px 0 rgba(0,0,0,.35);
  --subhead-bg: rgba(255,255,255,.05);
}

/* ---- dubTC SKIN: black with a restrained green cast — the brand look.
   Toned down (Luke 2026-07-16), then blacker + less green (2026-07-19),
   then lifted to the former high-contrast values (2026-08-11). ---- */
html[data-theme="dubtc"] {
  --bg:        #050706;
  --ink:       #f2fbf6;
  --ink-soft:  #bdd6c9;
  --line:      rgba(0,230,118,.32);
  --pane-body: rgba(0,0,0,.32);
  --ring:      rgba(0,230,118,.55);
  --chip:      rgba(0,230,118,.05);
  --chip-ink:  #8fa79a;
  --chip-on:   rgba(0,230,118,.18);
  --chip-on-ink:#6fe8ac;
  --red:       #ff8177;
  --red-fill:  rgba(214,58,46,.18);
  --red-ring:  rgba(214,58,46,.6);
  --pane-grad:   linear-gradient(135deg, rgba(15,25,19,.94), rgba(10,16,12,.92) 42%, rgba(12,20,15,.94));
  --pane-shadow: inset 0 1px 0 rgba(0,230,118,.06), 0 0 34px rgba(0,230,118,.03), 0 14px 44px rgba(0,0,0,.65);
  --head-grad:   linear-gradient(180deg, rgba(0,230,118,.10), rgba(0,230,118,.02));
  --head-grad-soft: linear-gradient(180deg, rgba(0,230,118,.07), rgba(0,230,118,.02));
  --btn-grad:    linear-gradient(180deg, rgba(27,42,33,.92), rgba(18,30,23,.9));
  --btn-hl:      inset 0 1px 0 rgba(0,230,118,.09);
  --btn-red-grad:linear-gradient(180deg, rgba(96,36,31,.92), rgba(72,27,23,.88));
  --field-bg:    rgba(0,230,118,.035);
  --surface:     rgba(0,230,118,.028);
  --surface-soft:rgba(0,230,118,.024);
  --seg-bg:      rgba(0,230,118,.035);
  --toast-bg:    rgba(10,17,13,.97);
  --dlg-grad:    linear-gradient(135deg, rgba(12,21,16,.98), rgba(8,14,10,.97));
  --dlg-shadow:  0 0 40px rgba(0,230,118,.05), 0 18px 60px rgba(0,0,0,.75);
  --inset-body:  inset 0 2px 7px rgba(0,0,0,.5);
  --hover:       rgba(0,230,118,.06);
  --neon:       #00e676;                 /* the brand green stays */
  --grain-op:   .045;
  --stripe:     rgba(0,230,118,.035);
  --btn-press:  inset 0 -1.5px 0 rgba(0,0,0,.4);
  --subhead-bg: rgba(0,230,118,.06);
  --opt-bg:      #0c1510;   /* opaque — see the :root note */
  --opt-ink:     #f2fbf6;
  --sb-thumb:    rgba(0,230,118,.30);
  --sb-thumb-hi: rgba(0,230,118,.52);
}

* { box-sizing: border-box; }
/* the grain: fixed, non-interactive, and faint enough to read as material
   rather than pattern. One SVG noise tile, opacity per skin. NOTE: the
   selector must be the PSEUDO alone — a stray `html,` here once applied
   fixed-position + 3% opacity to the whole document (2026-08-15). */
html::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 9999;
  opacity: var(--grain-op, 0);
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}
body { margin: 0; }
body {
  font-family: 'Roboto', system-ui, sans-serif;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}
/* Form controls do NOT inherit font-family — without this, inputs/selects/
   buttons fall back to the system face (Luke 2026-07-19: Roboto across the
   board). */
input, select, textarea, button { font-family: 'Roboto', system-ui, sans-serif; }
/* Flat gray background (test) — no image layer. When a tool is embedded
   (iframe inside another tool) its body stays transparent so the parent
   page's single background shows through, never a second one. */
html.embed body { background: transparent !important; }

/* ---- standard chrome (2026-08-09) ----
   EVERY page on dubtc-core carries the SAME top bar: brand -> home, the
   sitenav (core's initStaffNav injects the tier-gated Staff item), and the
   settings gear. The root pages ship identical inline copies of these
   rules (values must match); tools pages lean on this shared block. An
   embedded tool (iframe, html.embed) never shows a second nav. */
.topbar { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap;
  /* THE hero enrichment, once per page (Luke 2026-08-16: "just one hero on
     each page" — the outer layer carries the texture; sub-headers inside
     tools never repeat it). .pane-head keeps its original treatment because
     it IS a page's hero band where it appears. */
  background:
    repeating-linear-gradient(90deg, var(--stripe) 0 1px, transparent 1px 3px),
    var(--head-grad);
  border-bottom: 1px solid var(--line);
  padding: 8px 10px;
  border-radius: var(--radius);
}
.brand { font: 700 15px 'Rajdhani', 'Roboto', sans-serif; letter-spacing: .04em; text-decoration: none; color: var(--ink); }
.brand b { color: var(--neon); }
.sitenav { display: flex; gap: 2px; flex-wrap: wrap; }
.sitenav a { font: 500 12px 'Roboto',sans-serif; color: var(--ink-soft); text-decoration: none;
  padding: 5px 9px; border-radius: var(--radius); }
.sitenav a.on { color: var(--ink); font-weight: 700; border-bottom: 2px solid var(--neon); }
.sitenav a:hover { background: var(--hover); }
/* The gear is the ONLY identity affordance (Luke 2026-08-10) and it sits
   top-right on every page — the standalone auth chip and its
   #dubtc-auth-slot are gone site-wide. */
.topbar .themes { margin-left: auto; }
/* tools pages have no body padding (.wrap pads the pane) — the .toolpage
   body modifier gives the bar its own gutter instead */
body.toolpage .topbar { padding: 10px 16px 0; margin-bottom: 0; }
html.embed .topbar { display: none !important; }

/* ---- global site search (2026-08-12, dubtc-core initSiteSearch) ----
   Luke: the homepage's competitor search becomes "a search bar at the top bar
   that's on every page that we have that top bar… a general site search —
   events, camps, leagues, and competitors". Core injects it immediately left
   of the gear, so the gear stays the far-right item everywhere.

   The two `margin-left:auto` rules would otherwise fight: every root page
   ships its own inline copy of `.topbar .themes { margin-left: auto }`, and
   two auto margins would split the slack and float the field mid-bar. The
   three-class selector below outranks those inline copies without needing
   !important or an edit to nine pages. */
.topbar .sitesearch { position: relative; margin-left: auto; flex: 0 1 250px; min-width: 132px; }
.topbar .sitesearch ~ .themes { margin-left: 8px; }
.sitesearch .ss-q { padding: 6px 9px; font-size: 12px; }
.sitesearch .ss-q::-webkit-search-cancel-button { cursor: pointer; }
.ssres {
  position: absolute; top: calc(100% + 5px); right: 0; z-index: 390;
  width: min(320px, 84vw); max-height: 62vh; overflow-y: auto; text-align: left;
  background: var(--dlg-grad); border: 1px solid var(--ring);
  border-radius: var(--radius); box-shadow: var(--dlg-shadow);
}
.ssres[hidden] { display: none; }
/* one line per kind so a viewer can always tell WHAT they are looking at */
.ss-grp { font: 700 9px 'Roboto',sans-serif; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-soft); padding: 8px 10px 4px; border-top: 1px solid var(--line); }
.ssres .ss-grp:first-child { border-top: 0; }
.ss-grp i { font-style: normal; font-weight: 500; letter-spacing: 0; text-transform: none; }
.ss-r { display: flex; gap: 8px; align-items: baseline; padding: 6px 10px;
  font: 500 12px 'Roboto',sans-serif; color: var(--ink); text-decoration: none; }
.ss-r small { color: var(--ink-soft); margin-left: auto; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-width: 55%; }
.ss-n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ss-r:hover, .ss-r:focus { background: var(--hover); outline: none; }
.ss-r:focus { box-shadow: inset 2px 0 0 var(--neon); }
.ss-note { padding: 9px 10px; font: 400 11px 'Roboto',sans-serif; color: var(--ink-soft); line-height: 1.5; }

/* generic horizontal-scroll container for dense admin tables — never let a
   wide table force the PAGE to scroll sideways */
.scrollx { overflow-x: auto; }

/* ---- shell ---- */
/* Full-width: tools use the whole browser width (Luke 2026-07-15). The table
   builder needs the room; card-builder rows just get more breathing space. A
   little extra side padding on wide screens keeps content off the edges. */
.wrap { max-width: none; margin: 0 auto; padding: 1.25rem 1rem 6rem; }
@media (min-width: 60rem) { .wrap { padding-left: 1.5rem; padding-right: 1.5rem; } }

/* Sheen (glossy) finish, not frost: semi-opaque green-tinted fill with a
   diagonal light sweep + a bright top highlight; squared edges. */
.pane {
  border: 1px solid var(--ring);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--pane-grad);
  box-shadow: var(--pane-shadow);
}

.pane-head {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 15px 16px;
  background:
    repeating-linear-gradient(90deg, var(--stripe) 0 1px, transparent 1px 3px),
    var(--head-grad);
  border-bottom: 1px solid var(--line);
}
.pane-head .h-main { min-width: 0; flex: 1; }

.pane-title { font-size: 17px; font-weight: 700; letter-spacing: -.01em; overflow-wrap: anywhere; }
.pane-sub   { font-size: 12px; color: var(--ink-soft); margin-top: 2px; overflow-wrap: anywhere; }

/* Sub-header layer — a slight ground shift under item-box titles, site-wide.
   Quiet by design: color only, no pattern. The tint runs EDGE TO EDGE of the
   box it sits in (Luke 2026-08-16) — negative margins bleed through each
   container's known padding; only the top corners keep the box radius. */
.hhead, .lbtitle, .btitle, .sechead, .cat > h2, .card > h3,
.lcard > h3, .rcard > b, .wshead {
  background: var(--subhead-bg);
  border-radius: var(--radius) var(--radius) 0 0;
  padding: 6px 9px;
  border-bottom: 1px solid var(--line);
}
/* per-container bleeds (container padding is knowable per class) */
.fcard  > .hhead   { margin: -12px -14px 4px; padding: 8px 14px; }
.lbboard > .lbtitle{ margin: -10px -12px 7px; padding: 7px 12px; }
.board  > .btitle  { margin: -16px -16px 6px; padding: 10px 16px; }
.cat    > h2       { margin: -12px -14px 6px; padding: 8px 14px; }
.card   > h3       { margin: -12px -12px 8px; padding: 8px 12px; }
.lcard  > h3       { margin: -12px -14px 6px; padding: 8px 14px; }
.rcard  > b        { display: block; margin: -8px -9px 6px; padding: 7px 9px; }

/* ---- rows (Discord-Section layout: text left, one button right) ---- */
.rows > * { border-top: 1px solid var(--line); }
.rows > :first-child { border-top: 0; }

details.sec > summary { list-style: none; cursor: pointer; }
details.sec > summary::-webkit-details-marker { display: none; }
details.sec[open] > summary .chev { transform: rotate(180deg); }
.chev { transition: transform .15s; color: var(--ink-soft); font-size: 11px; flex: 0 0 auto; }

.sec-sum {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px;
}
.sec-sum:hover { background: var(--hover); }
.r-title { font-size: 14px; font-weight: 500; min-width: 0; overflow-wrap: anywhere; }
.r-chips { margin-left: auto; display: flex; gap: 6px; align-items: center; min-width: 0; }

/* Expanded panels sit slightly DARKER/recessed than the base pane. */
.sec-body {
  background: var(--pane-body);
  border-top: 1px solid var(--line);
  box-shadow: var(--inset-body);
}
.sec-body > * { border-top: 1px solid var(--line); }
.sec-body > :first-child { border-top: 0; }

.action, .row-link {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 16px;
}
.a-main { min-width: 0; flex: 1; }
.a-label { font-size: 14px; font-weight: 500; overflow-wrap: anywhere; }
.a-desc  { font-size: 12px; color: var(--ink-soft); margin-top: 2px; line-height: 1.4; overflow-wrap: anywhere; }

/* ---- chips ---- */
.chip {
  font-size: 11px; padding: 2px 8px; border-radius: var(--radius);
  background: var(--chip); color: var(--chip-ink); font-weight: 500; white-space: nowrap;
}

/* Embedded sub-tool (card builder / live results) inside an expandable row. */
.embed-frame { width: 100%; height: 72vh; border: 0; display: block; background: transparent; }
.embed-open { display: flex; justify-content: flex-end; padding: 8px 12px; border-top: 1px solid var(--line); }
.embed-open a { font-size: 12px; color: var(--chip-on-ink); text-decoration: none; }
.chip.on { background: var(--chip-on); color: var(--chip-on-ink); }

/* ---- buttons: exactly two schemes ---- */
.btn {
  width: 116px; padding: 8px; border-radius: var(--radius); text-align: center;
  font: 500 13px/1 'Roboto', sans-serif; cursor: pointer;
  color: var(--ink);
  background: var(--btn-grad);
  border: 1px solid var(--ring);
  box-shadow: var(--btn-hl), var(--btn-press);
  transition: filter .12s;
}
.btn:hover { filter: brightness(1.05); }
.btn:active:not([disabled]) {
  box-shadow: inset 0 2px 5px rgba(0,0,0,.22);
  filter: brightness(.97);
}
.btn.red {
  color: var(--red);
  background: var(--btn-red-grad);
  border-color: var(--red-ring);
}
.btn[disabled] { opacity: .4; cursor: default; box-shadow: none; }
.btn[disabled]:hover { filter: none; }

/* small utility */
.spin { display: inline-block; animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* gate + toasts (shared) */
.gate { max-width: 26rem; margin: 6rem auto 0; padding: 1.5rem; text-align: center; }
.gate h1 { font-size: 20px; margin: 0 0 6px; }
.gate p  { font-size: 13px; color: var(--ink-soft); line-height: 1.5; margin: 0; }
.gate .err { color: var(--red); font-size: 13px; margin-top: 1rem; }

#toast-wrap { position: fixed; bottom: 1rem; left: 50%; transform: translateX(-50%); z-index: 50; display: flex; flex-direction: column; gap: .5rem; }
.toast {
  padding: 9px 16px; border-radius: var(--radius); font-size: 13px;
  background: var(--toast-bg); color: var(--ink);
  border: 1px solid var(--ring);
  box-shadow: 0 6px 20px rgba(6,40,22,.18);
  animation: toast-in .15s ease-out;
}
.toast.err { background: var(--red-fill); border-color: var(--red-ring); color: var(--red); }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.busy { opacity: .5; pointer-events: none; }

/* =====================================================================
   Shared components — used by card builder / live results / future tools.
   ===================================================================== */

/* tabs */
.tabs { display: flex; gap: 4px; }
.tab {
  padding: 8px 14px; font: 500 13px 'Roboto', sans-serif; cursor: pointer;
  background: transparent; border: 0; border-bottom: 2px solid transparent;
  color: var(--ink-soft);
}
.tab.active { color: var(--ink); border-bottom-color: var(--neon); }

/* form fields */
.field {
  width: 100%; padding: 7px 9px; border-radius: var(--radius);
  font: 400 13px 'Roboto', sans-serif; color: var(--ink);
  background: var(--field-bg); border: 1px solid var(--ring);
}
.field:focus { outline: none; border-color: var(--neon); }
select.field { cursor: pointer; }
/* The dropdown ITSELF, not the closed control. A native option list is an OS
   popup: it reads background-color/color off the select and cannot use our
   translucent --field-bg, so it fell back to a white popup while the ink
   stayed theme-coloured — light-gray-on-white, near-unreadable, in all three
   themes (Luke 2026-08-12). Opaque pair, stated on both the select and its
   options because Windows reads it from different places than macOS does. */
select.field,
select.field option,
select.field optgroup {
  background-color: var(--opt-bg);
  color: var(--opt-ink);
}
select.field option:checked { font-weight: 700; }

/* ---- dubTC scrollbars, for scrollers INSIDE the page ----
   The window's own bar is left native on purpose (Luke: "the side scroll bar
   is fine for general use"). Everything that scrolls within a page — tables,
   panels, dialogs, code blocks — was showing the OS default. html/body are
   excluded so the page-level bar keeps the platform behaviour people expect. */
*:not(html):not(body) {
  scrollbar-width: thin;                              /* Firefox */
  scrollbar-color: var(--sb-thumb) transparent;
}
*:not(html):not(body)::-webkit-scrollbar { width: 10px; height: 10px; }
*:not(html):not(body)::-webkit-scrollbar-track { background: transparent; }
*:not(html):not(body)::-webkit-scrollbar-corner { background: transparent; }
*:not(html):not(body)::-webkit-scrollbar-thumb {
  background: var(--sb-thumb);
  border-radius: 999px;
  /* transparent border + padding-box keeps the thumb slim inside its gutter
     instead of filling the full 10px like a 1999 Windows bar */
  border: 2px solid transparent;
  background-clip: padding-box;
}
*:not(html):not(body)::-webkit-scrollbar-thumb:hover { background: var(--sb-thumb-hi); }
/* Label-over-field: a COLUMN flex so the caption text always stacks cleanly
   above the control — inline text + inline-block fields used to share a line
   box and overlap (Luke 2026-07-16). min-width:0 lets wide selects (long
   option lists) shrink to the cell instead of overflowing it. */
.lbl { font-size: 11px; color: var(--ink-soft); display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.lbl .field { margin-top: 0; }
.lbl select, .lbl input, .lbl textarea { min-width: 0; max-width: 100%; }

/* competitor-corner identity (data, not buttons) */
.corner-red  { border-left: 3px solid #d64236; }
.corner-blue { border-left: 3px solid #2f6bd6; }
.tx-red  { color: #b23a30; }
.tx-blue { color: #2857ad; }

/* odds bar */
.oddsbar { height: 6px; border-radius: var(--radius); overflow: hidden; display: flex; }
.oddsbar .red  { background: #d64236; }
.oddsbar .blue { background: #2f6bd6; }

/* segmented result control (Red / Blue / Draw / —) */
.seg-wrap { display: flex; border: 1px solid var(--ring); border-radius: var(--radius); overflow: hidden; }
.seg {
  flex: 1; padding: 8px 4px; font: 600 12px 'Roboto', sans-serif; cursor: pointer;
  background: var(--seg-bg); color: var(--ink-soft); border: 0; border-left: 1px solid var(--line);
}
.seg:first-child { border-left: 0; }
.seg.on-red  { background: #d64236; color: #fff; }
.seg.on-blue { background: #2f6bd6; color: #fff; }
.seg.on-draw { background: #6b7a70; color: #fff; }
.seg.on-none { background: var(--chip); color: var(--ink); }

/* dialogs — the sheen pane look */
dialog.dlg {
  padding: 0; color: var(--ink);
  border: 1px solid var(--ring); border-radius: var(--radius);
  background: var(--dlg-grad);
  box-shadow: var(--dlg-shadow);
  max-width: 94vw;
}
dialog.dlg::backdrop { background: rgba(6,26,16,.45); }
.dlg-head {
  position: sticky; top: 0; z-index: 1; padding: 14px 16px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  background: var(--head-grad-soft);
  border-bottom: 1px solid var(--line);
}
.dlg-title { font-size: 14px; font-weight: 700; }
.x-btn { background: transparent; border: 0; color: var(--ink-soft); font-size: 15px; cursor: pointer; padding: 2px 6px; }
.x-btn:hover { color: var(--ink); }

/* list rows (competitor picker, pool) */
.list-row {
  display: block; width: 100%; text-align: left; cursor: pointer;
  padding: 9px 12px; border-radius: var(--radius);
  background: transparent; border: 0; color: var(--ink); font-family: 'Roboto', sans-serif;
}
.list-row:hover { background: var(--hover); }
.list-row[disabled] { opacity: .4; cursor: default; }
.list-row.sel { background: var(--chip-on); }

/* matchup cell grid — aligns red names in one column, blue in another across
   every row (card builder + live results). num | red | mid | blue | end. */
.mm-row {
  display: grid;
  grid-template-columns: 30px minmax(0,1fr) 46px minmax(0,1fr) auto;
  align-items: center; gap: 8px;
}
.mm-name {
  min-width: 0; text-align: left; padding: 3px 5px; border-radius: var(--radius);
  background: transparent; border: 0; cursor: pointer;
  font: 500 13px 'Roboto', sans-serif; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mm-name:hover { background: var(--hover); }
.mm-name.empty { color: var(--chip-on-ink); border: 1px dashed var(--ring); font-weight: 500; }
.mm-name.static { cursor: default; }
.mm-name.static:hover { background: transparent; }
.mm-name.win { font-weight: 700; }
.mm-mid { text-align: center; font-size: 10px; color: var(--ink-soft); }
.mm-end { display: flex; align-items: center; gap: 5px; justify-self: end; }

/* small accent tag (placement / winner) */
.tag { font-size: 10px; padding: 1px 6px; border-radius: var(--radius); background: var(--chip-on); color: var(--chip-on-ink); }
.tag.warn { background: rgba(214,58,46,.14); color: var(--red); }

/* small ghost icon button (⇄ change, etc.) — padding gives the glyph a real
   hit area at every size; the glyph itself stays 13px. */
.icon-btn { background: transparent; border: 0; color: var(--ink-soft); cursor: pointer; font-size: 13px; padding: 6px 8px; }
.icon-btn:hover { color: var(--ink); }

/* muted helper text */
.muted { color: var(--ink-soft); }
.mono-sm { font-size: 11px; color: var(--ink-soft); }

/* =====================================================================
   Table builder — reusable configurable table + column picker.
   Users choose which columns show; rows expand for detail/editing.
   ===================================================================== */
.tbl-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); }
table.tbl { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.tbl thead th {
  position: sticky; top: 0; z-index: 1;
  text-align: left; font-weight: 600; color: var(--ink-soft);
  padding: 8px 10px; white-space: nowrap;
  background: var(--head-grad-soft);
  border-bottom: 1px solid var(--line);
}
/* drag-to-resize column grips (dubtc-tbl.js) — a thin hit zone on each
   header's right edge; the visible line only appears on hover. */
.tbl thead th { position: relative; }
.col-grip { position: absolute; top: 0; right: -5px; width: 10px; height: 100%;
            cursor: col-resize; user-select: none; touch-action: none; z-index: 2; }
.col-grip:hover, .col-grip:active {
  background: linear-gradient(to right, transparent 4px, var(--neon) 4px, var(--neon) 6px, transparent 6px);
}
/* The LAST column's grip must not poke past the table edge — a 5px overhang
   put a permanent phantom horizontal scrollbar on EVERY table (2026-07-19). */
.tbl thead th:last-child .col-grip { right: 0; width: 6px; }
.tbl thead th:last-child .col-grip:hover, .tbl thead th:last-child .col-grip:active {
  background: linear-gradient(to right, transparent 2px, var(--neon) 2px, var(--neon) 4px, transparent 4px);
}
/* Touch devices: the 10px edge grips sit exactly where a finger tries to
   scroll the table, and touch-action:none on them TRAPS the pan. Resize is a
   pointer affordance — hide it where the pointer is a finger (dubtc-tbl.js
   also skips binding the header drag-reorder there). */
@media (pointer: coarse) {
  .col-grip { display: none; }
}
/* hold-and-drag column reorder (dubtc-tbl.js) — dragged header dims, a neon
   insertion edge marks where the column will land. */
.tbl.col-reordering { cursor: grabbing; user-select: none; }
th.col-dragging { opacity: .5; }
th.col-drop-left  { box-shadow: inset 3px 0 0 var(--neon); }
th.col-drop-right { box-shadow: inset -3px 0 0 var(--neon); }
/* .numc, not .num — the matchmaking card builder's local <style> claims .num
   for its 30px bout-number chip; a bare .num here would inherit that chip. */
.tbl thead th.numc, .tbl tbody td.numc { text-align: right; font-variant-numeric: tabular-nums; }
/* vertical dividers between columns (Luke 2026-07-16) — detail rows excluded
   (their single full-width cell shouldn't carry a stray divider). */
.tbl thead th:not(:last-child), .tbl tbody tr:not(.detail) > td:not(:last-child) {
  border-right: 1px solid var(--line);
}
.tbl tbody tr { border-top: 1px solid var(--line); cursor: pointer; }
.tbl tbody tr:first-child { border-top: 0; }
.tbl tbody tr:hover { background: var(--hover); }
.tbl tbody tr.open { background: var(--hover); }
.tbl tbody td { padding: 7px 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 220px; }
.tbl td.name { font-weight: 500; }
.tbl tr.detail > td { padding: 0; background: var(--pane-body); box-shadow: var(--inset-body); cursor: default; }
.tbl tr.detail:hover { background: var(--pane-body); }

/* theme switcher (Light / Dark / dubTC) — shared by every tool page. Pages
   add the pre-paint snippet in <head> + the #themes buttons; dubtc-theme.js
   logic is small enough that each page carries the 8-line wire-up. */
.themes { display: flex; border: 1px solid var(--ring); border-radius: var(--radius); overflow: hidden; flex: 0 0 auto; }
.themes button { padding: 6px 10px; font: 500 11px 'Roboto',sans-serif; cursor: pointer; border: 0;
                 background: var(--seg-bg); color: var(--ink-soft); border-left: 1px solid var(--line); }
.themes button:first-child { border-left: 0; }
.themes button.on { background: var(--chip-on); color: var(--chip-on-ink); font-weight: 700; }
/* embedded tools follow the parent page's stored theme; no second switcher */
html.embed .themes { display: none; }

/* ---- user settings panel (2026-08-10, dubtc-core initSettings) ----
   Core replaces the #themes button row with a gear button + dropdown at
   init; the .uset modifier lets the dropdown escape the switcher's
   overflow:hidden. The gear inherits the .themes button look. It is also
   the site's ONLY signed-in indicator — hence the avatar/initial on the
   trigger and the Account block in the panel. */
#themes.uset { position: relative; overflow: visible; }
/* pages with no .topbar at all (core mounts its own host) — pin top-right */
#themes.uset-float { position: fixed; top: 10px; right: 12px; z-index: 401;
  background: var(--seg-bg); }
#uset-btn { display: inline-flex; align-items: center; gap: 6px; }
#uset-btn:hover { background: var(--hover); color: var(--ink); }
#uset-btn img { width: 16px; height: 16px; border-radius: 50%; display: block; }
#uset-btn svg { display: block; }
#uset-btn.is-in { color: var(--ink); }
/* no Discord avatar? the display name's initial still says "that's you" */
.uset-ini { display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 50%; background: var(--chip-on);
  color: var(--chip-on-ink); font: 700 9px 'Roboto',sans-serif; flex: 0 0 auto; }
.sp-user .uset-ini { width: 22px; height: 22px; font-size: 11px; }
/* dev is a different login realm — the gear wears a mark so you never wonder */
#uset-btn.is-dev::after { content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--neon); flex: 0 0 auto; }
#uset-panel {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 400;
  width: 252px; padding: 10px 12px 12px; text-align: left;
  background: var(--dlg-grad); border: 1px solid var(--ring);
  border-radius: var(--radius); box-shadow: var(--dlg-shadow);
  font: 500 12px 'Roboto', sans-serif; color: var(--ink);
}
#uset-panel[hidden] { display: none; }
.sp-h { font: 700 10px 'Roboto',sans-serif; letter-spacing: .14em; text-transform: uppercase;
        color: var(--ink-soft); margin: 12px 0 6px; }
#uset-panel .sp-h:first-child { margin-top: 0; }
.sp-seg { display: flex; border: 1px solid var(--ring); border-radius: var(--radius); overflow: hidden; }
.sp-seg button { flex: 1; padding: 7px 4px; font: 500 11px 'Roboto',sans-serif; cursor: pointer;
  border: 0; background: var(--seg-bg); color: var(--ink-soft); border-left: 1px solid var(--line); }
.sp-seg button:first-child { border-left: 0; }
.sp-seg button.on { background: var(--chip-on); color: var(--chip-on-ink); font-weight: 700; }
.sp-user { display: flex; align-items: center; gap: 8px; padding: 2px 0 6px;
  font: 700 12px 'Roboto',sans-serif; min-width: 0; }
.sp-user img { width: 22px; height: 22px; border-radius: 50%; flex: 0 0 auto; }
.sp-user span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-user .tier { font: 700 9px 'Roboto',sans-serif; text-transform: uppercase; overflow: visible;
  padding: 1px 5px; border-radius: 8px; background: var(--chip-on); color: var(--chip-on-ink); }
.sp-link { display: block; width: 100%; text-align: left; padding: 8px; margin: 0; border: 0;
  background: transparent; color: var(--ink); font: 500 12px 'Roboto',sans-serif;
  cursor: pointer; text-decoration: none; border-radius: var(--radius); box-sizing: border-box; }
.sp-link:hover { background: var(--hover); }
/* signed-out: the one sign-in button on the page, so it reads as an action */
.sp-cta { border: 1px solid var(--ring); text-align: center; font-weight: 700; }
/* env honesty line (#dev = a separate Supabase project, separate sessions) */
.sp-env { font: 400 10px 'Roboto',sans-serif; line-height: 1.5; color: var(--ink-soft);
  border: 1px dashed var(--ring); border-radius: var(--radius);
  padding: 6px 8px; margin: 0 0 8px; }
.sp-env b { color: var(--ink); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; }

/* ---- house text size ----
   Luke 2026-08-11: "also remove the text size tooling, use large as the
   default". Large was a body zoom because the suite's type is px-based — a
   root font-size bump alone scales nothing — so the same zoom is now
   unconditional and there is no picker. Framed tools are still excluded —
   ?embed=1 tools (html.embed) and anything core detects as living inside a
   frame (html.framed, e.g. HQ's panes): the parent page's zoom already
   scales the iframe box, and zooming inside too would double it. */
html:not(.embed):not(.framed) body { zoom: 1.1; }

/* column-picker button + dialog */
.colpick-list { display: flex; flex-direction: column; gap: 2px; padding: 8px; overflow-y: auto; max-height: 62vh; }
.colpick-group { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-soft); padding: 8px 8px 3px; }
.colpick-row { display: flex; align-items: center; gap: 8px; padding: 7px 8px; border-radius: var(--radius); cursor: pointer; }
.colpick-row:hover { background: var(--hover); }
.colpick-row input { accent-color: var(--neon); }
.colpick-row .sub { margin-left: auto; }
.colpick-sub { margin: 0 8px 6px 30px; padding: 8px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-soft); }

/* ---- house mobile pass (≤600px; desktop untouched) — the root pages'
   recipe applied suite-wide: comfortable tap targets, 16px inputs (kills the
   iOS zoom-on-focus), headers that wrap instead of clipping. Tables ride
   inside .tbl-wrap / .scrollx containers, so they scroll themselves. ---- */
@media (max-width: 600px) {
  .sitenav a { padding: 9px 10px; }
  .themes button { padding: 9px 12px; }
  input.field, select.field, textarea.field { font-size: 16px; }
  .pane-head { flex-wrap: wrap; }
  .wrap { padding-left: .6rem; padding-right: .6rem; }
  body.toolpage .topbar { padding: 10px 10px 0; }
  /* The gear rides the logo's row, never the nav's (Luke 2026-08-12: "the cog
     should be on the top right, same row as the dubtc logo"). DOM order is
     brand -> sitenav -> themes, and six nav links are wide enough to push the
     gear onto a second line, where it landed under the tool banner. Order the
     brand and gear onto row one, force a break after the gear, and let the
     nav take the full width of row two. margin-left:auto (line 161) still
     does the right-pinning. */
  .topbar .brand   { order: 1; }
  .topbar .themes  { order: 2; }
  .topbar::after   { content: ""; order: 2; flex-basis: 100%; height: 0; }
  .topbar .sitenav { order: 3; flex-basis: 100%; }
  /* The search takes its OWN full-width row below the nav rather than
     competing for the logo's row — a 250px field wedged next to the gear at
     375px would either shove the gear off row one (undoing the fix above) or
     shrink to a useless stub. margin-left:auto is dropped so it starts at the
     gutter, and the dropdown spans the row instead of hanging off the right. */
  .topbar .sitesearch { order: 4; flex-basis: 100%; margin-left: 0; }
  /* …and with the field no longer holding the slack, the gear needs its own
     auto margin back or it collapses next to the logo instead of pinning
     top-right (the desktop rule above hands it a fixed 8px gap). */
  .topbar .sitesearch ~ .themes { margin-left: auto; }
  .sitesearch .ss-q { font-size: 16px; padding: 9px 10px; }  /* 16px = no iOS zoom-on-focus */
  .ssres { width: auto; left: 0; right: 0; }
  .ss-r { padding: 10px; }
  /* settings panel becomes a full-width bottom sheet */
  #uset-panel { position: fixed; left: 0; right: 0; top: auto; bottom: 0; width: auto;
    max-height: 76vh; overflow-y: auto; border-left: 0; border-right: 0; border-bottom: 0;
    border-radius: 0; padding-bottom: max(14px, env(safe-area-inset-bottom)); }
  .sp-seg button { padding: 10px 4px; }
  .sp-link { padding: 11px 8px; }
  /* ---- no page zoom on phones (2026-08-16 mobile pass) ----
     The house zoom (1.1, see "house text size" above) shrinks the effective
     viewport ~9% on a phone — every breakpoint fires late and every box gets
     narrower. Cap it at 1 here and hand the tiniest text tiers (+1px each)
     back, so mobile type doesn't shrink net. Desktop is untouched. */
  html:not(.embed):not(.framed) body { zoom: 1; }
  .chip { font-size: 12px; }
  .ss-grp { font-size: 10px; }
  .ss-note { font-size: 12px; }
  .lbl { font-size: 12px; }
  .mm-mid { font-size: 11px; }
  .tag { font-size: 11px; }
  .mono-sm { font-size: 12px; }
  .chev { font-size: 12px; }
  .sp-h { font-size: 11px; }
  .sp-env { font-size: 11px; }
  .sp-seg button { font-size: 12px; }
  .themes button { font-size: 12px; }
  .uset-ini { font-size: 10px; }
  .sp-user .tier { font-size: 10px; }
  .colpick-group { font-size: 11px; }
  /* ---- comfortable tap targets, centrally (2026-08-16 mobile pass) ----
     .mini is defined per page but every tool loads this sheet, so the bump
     lands suite-wide. Icon/x buttons get a square hit box; glyphs unchanged. */
  .btn, .seg, .tab { min-height: 40px; }
  .mini { min-height: 40px; padding: 6px 10px; }
  .icon-btn, .x-btn { min-height: 40px; min-width: 40px; }
}
