/* ═══════════════════════════════════════════════════════════════════════════
   Console stylesheet

   Dark slate, flat, white hairline rules instead of panels. Everything visual
   comes from the custom properties below — change one value, it updates
   everywhere.

     1. Palette
     2. Base
     3. Shell (sidebar + main)
     4. Blocks, stats, tables
     5. Forms
     6. Buttons, badges, notices, toasts
     7. Sign in
     8. Small screens
   ═══════════════════════════════════════════════════════════════════════════ */


/* ─── 1. Palette ────────────────────────────────────────────────────────── */

:root {
  /* Ground up: page, slightly raised (inputs), and the two rule weights.
     Slate rather than near-black. The rules are white at low opacity so they
     sit on top of whatever they cross and keep the same weight everywhere. */
  --bg:        #1b1f26;
  --bg-input:  #252a33;
  --line:      rgba(255, 255, 255, .38);
  --line-soft: rgba(255, 255, 255, .18);

  /* Text, brightest to faintest */
  --text:       #f3f5f7;
  --text-dim:   #bcc3cb;
  --text-faint: #8b939d;

  /* Green. Used only where it carries meaning: active nav, focus, ok, links. */
  --accent:      #9ed4ae;
  --accent-dim:  #7fb994;
  --accent-wash: rgba(158, 212, 174, .14);

  /* Lay. The other side of the pair, so a different hue from the green
     entirely — back and lay should never be mistaken for each other at a
     glance. Brighter means best, same as green does on the back side. */
  --lay:      #9dbfe4;
  --lay-best: #c3ddfa;

  /* Bet365 — a second feed, not a fourth kind of price. Its own hue so it is
     never read as "best back" green or "lay" blue. */
  --b365: #c3a8de;

  /* Status */
  --bad:  #e0919b;
  --warn: #d6ba80;

  --radius: 4px;
  --sidebar-w: 200px;

  --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "Cascadia Code", Consolas, monospace;
}


/* ─── 2. Base ───────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html { color-scheme: dark; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.55;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; font-weight: 600; line-height: 1.3; }
h1 { font-size: 1.15rem; letter-spacing: -0.01em; }

p { margin: 0 0 .85rem; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

code, pre, .mono { font-family: var(--mono); font-size: .85em; }

/* Small uppercase label — the only recurring typographic device */
.eyebrow-label {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.dim    { color: var(--text-dim); }
.faint  { color: var(--text-faint); }
.small  { font-size: .8rem; }
.center { text-align: center; }
.nowrap { white-space: nowrap; }
.hidden { display: none !important; }


/* ─── 3. Shell ──────────────────────────────────────────────────────────── */

.shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  min-height: 100vh;
}

/* Sidebar ---------------------------------------------------------------- */

.sidebar {
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.sidebar__nav {
  flex: 1;
  padding: 1.5rem .5rem;

  /* A column, so a section marked foot:true in lib/nav.js can be pushed
     down to sit above Sign out */
  display: flex;
  flex-direction: column;
}

.sidebar__section { padding: 0 .65rem .4rem; }
.sidebar__section:not(:first-child) { margin-top: 1.5rem; }

/* Beats the rule above, which would otherwise pin it 1.5rem below the APIs */
.sidebar__nav .sidebar__section--foot { margin-top: auto; }

.sidebar__nav ul { list-style: none; margin: 0; padding: 0; }

.navlink {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .4rem .65rem;
  color: var(--text-dim);
  font-size: .875rem;
  border-left: 2px solid transparent;
}

.navlink:hover { color: var(--text); text-decoration: none; }

.navlink.is-active {
  color: var(--text);
  border-left-color: var(--accent);
}

.navlink__label { flex: 1; }

/* Small dot marking a page as wired up or still a placeholder */
.dot { width: 5px; height: 5px; border-radius: 50%; flex: 0 0 5px; }
.dot--live { background: var(--accent-dim); }
.dot--soon { background: var(--line); }

.sidebar__foot {
  padding: 1rem .9rem;
  border-top: 1px solid var(--line);
}

/* Main ------------------------------------------------------------------- */

.main { min-width: 0; }

.content {
  padding: 2rem 2.25rem 4rem;
  max-width: 1000px;
}

/* For pages that earn the extra width - the Discord page runs two columns */
.content--wide { max-width: 1280px; }

/* For a page with a sticky column: the usual deep bottom gutter would push
   the sticky element off the top of the screen at the very end of the scroll */
.content--flush { padding-bottom: 2rem; }

/* Page heading, in the content rather than a separate bar */
.page { margin-bottom: 2rem; }
.page p { margin: .15rem 0 0; color: var(--text-dim); font-size: .85rem; }

/* Heading with an action parked on the right */
.page--row {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
}

.page--row > div { flex: 1; min-width: 0; }
.page--row > .btn { flex: 0 0 auto; margin-top: .15rem; }


/* ─── 4. Blocks, stats, tables ──────────────────────────────────────────── */

/* A section of the page. A rule above it, nothing else. */
.block {
  border-top: 1px solid var(--line);
  padding: 1.5rem 0;
}

.block:last-child { padding-bottom: 0; }

.block__head {
  display: flex;
  align-items: baseline;
  gap: .9rem;
  margin-bottom: 1.1rem;
}

.block__head > :first-child { flex: 1; }

.block__head h2 {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* Stats — a row of label/value pairs, no boxes */
.stats {
  display: flex;
  flex-wrap: wrap;
  gap: 2.25rem;
  padding-bottom: 1.75rem;
}

.stat__label {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: .1rem;
}

.stat__value {
  font-size: 1.5rem;
  font-weight: 500;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}

.stat__value--ok  { color: var(--accent); }
.stat__value--bad { color: var(--bad); }

/* Tables ----------------------------------------------------------------- */

.table-wrap { overflow-x: auto; }

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: .85rem;

  /* Without a floor, narrow screens crush columns and every cell wraps into
     a tall tower. Below this the wrapper scrolls sideways instead. */
  min-width: 640px;
}

table.data--tight { min-width: 0; }

table.data th {
  text-align: left;
  padding: 0 .85rem .5rem 0;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

table.data td {
  padding: .55rem .85rem .55rem 0;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: top;
}

/* A th used as a row label rather than a column heading - same weight as the
   cell beside it, not the heavier rule a thead th gets */
table.data tbody th {
  width: 9rem;
  padding: .55rem .85rem .55rem 0;
  border-bottom: 1px solid var(--line-soft);
  vertical-align: top;
}

table.data tbody tr:last-child td,
table.data tbody tr:last-child th { border-bottom: 0; }
table.data th:last-child, table.data td:last-child { padding-right: 0; }

.empty {
  padding: 1.5rem 0;
  color: var(--text-faint);
  font-size: .85rem;
}

/* ─── Log detail page ─────────────────────────────────────────────────────
   The one place with actual bordered panels rather than hairlines - two
   side-by-side cards read better than two stacked rule-separated sections. */

.detailhead {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  flex-wrap: wrap;
  font-size: .875rem;
  margin-bottom: .3rem;
}

.detailhead__sep { color: var(--line); }

.panels {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1rem;
  margin-bottom: 1.5rem;
  align-items: start;
}

.panel {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem;
  min-width: 0;
}

.panel__title {
  font-size: 1rem;
  font-weight: 600;
  margin-bottom: .15rem;
}

.panel__sub {
  font-size: .76rem;
  color: var(--text-faint);
  margin-bottom: 1rem;
}

/* Label above value, for the sparse left-hand panel */
.pair { margin-bottom: 1rem; }
.pair:last-child { margin-bottom: 0; }

.pair__label {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: .2rem;
}

.pair__value { font-size: .875rem; word-break: break-word; }

/* The fields table inside a panel shouldn't force the 640px floor */
.panel table.data { min-width: 0; }

/* Expandable JSON on the log detail page. Unlike the table version this one
   gets the full content width and scrolls in both directions. */

details.jsonblock summary {
  cursor: pointer;
  color: var(--text-dim);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
}

details.jsonblock summary::-webkit-details-marker { display: none; }
details.jsonblock summary:hover { color: var(--accent); }

/* A caret that turns when the block is open */
details.jsonblock summary::before {
  content: '▸';
  font-size: .7rem;
  color: var(--text-faint);
}

details.jsonblock[open] summary::before { content: '▾'; }

details.jsonblock pre {
  margin: .6rem 0 0;
  padding: .85rem 1rem;
  background: var(--bg-input);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: auto;
  max-height: 26rem;
  font-size: .78rem;
  line-height: 1.5;
  color: var(--text);
  white-space: pre;
}

/* Collapsible raw JSON in the log table */
details.json summary {
  cursor: pointer;
  color: var(--text-dim);
  font-size: .8rem;
  white-space: nowrap;
  list-style: none;          /* drop the disclosure triangle - in a narrow */
}                            /* column it wraps onto its own line          */

details.json summary::-webkit-details-marker { display: none; }
details.json summary:hover { color: var(--accent); }

details.json pre {
  margin: .5rem 0 0;
  padding: .7rem;
  background: var(--bg-input);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow-x: auto;
  max-width: 420px;
  font-size: .76rem;
  color: var(--text-dim);
}


/* ─── 5. Forms ──────────────────────────────────────────────────────────── */

.field { margin-bottom: .9rem; }

.field > label {
  display: block;
  margin-bottom: .3rem;
  font-size: .78rem;
  color: var(--text-dim);
}

.field__hint { font-size: .74rem; color: var(--text-faint); margin-top: .25rem; }

/* A label with an on/off switch parked at the right-hand end of it */
.field > label.field__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .6rem;

  /* Pinned to the height a plain label takes (.78rem x 1.55 line-height) so
     the input below lines up with the field next to it */
  height: 1.21rem;
}

.field__toggle .toggle { font-size: .72rem; color: var(--text-faint); }

/* Sized under the label's own line box, so a field with a switch on it lines
   up with the plain field beside it instead of sitting a couple of px lower */
.field__toggle .toggle input {
  width: .8rem;
  height: .8rem;
  margin: 0;
  vertical-align: middle;
}

input:disabled { opacity: .45; cursor: not-allowed; }

input[type="text"],
input[type="password"],
input[type="number"],
input[type="search"],
input[type="file"],
select,
textarea {
  width: 100%;
  padding: .45rem .6rem;
  font: inherit;
  font-size: .875rem;
  color: var(--text);
  background: var(--bg-input);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent-dim);
}

input::placeholder { color: var(--text-faint); }

/* Marks a numeric field whose value doesn't parse */
input.is-bad { border-color: var(--bad); }

select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-faint) 50%),
                    linear-gradient(135deg, var(--text-faint) 50%, transparent 50%);
  background-position: calc(100% - 16px) 52%, calc(100% - 11px) 52%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 1.9rem;
}

/* A related set of fields. Separated by a hairline, not boxed. */
.group {
  padding: 1.1rem 0;
  border-top: 1px solid var(--line-soft);
}

.group__title {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: .8rem;
}

.row {
  display: grid;
  gap: .75rem;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}

.row--2 { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.row--3 { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
.row .field { margin-bottom: 0; }
.row { margin-bottom: 1rem; }

/* ─── Back / lay grid ─────────────────────────────────────────────────────
   Both bets as two rows against shared column headings, rather than two
   stacked blocks. Saves a lot of vertical space on the Discord page.        */

.betgrid {
  display: grid;
  grid-template-columns: 3.2rem 1fr 7.5rem 7.5rem;
  gap: .45rem .6rem;
  align-items: center;
  margin-bottom: 1rem;
}

.betgrid__col {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.betgrid__side {
  font-size: .78rem;
  color: var(--text-dim);
}

/* The select plus its "link" toggle, sharing one grid cell */
.betgrid__pick { display: flex; align-items: center; gap: .4rem; min-width: 0; }
.betgrid__pick select { flex: 1; min-width: 0; }

.linkbtn {
  flex: 0 0 auto;
  padding: .2rem .45rem;
  font: inherit;
  font-size: .72rem;
  color: var(--text-faint);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
}

.linkbtn:hover { color: var(--text); border-color: var(--text-faint); }

/* Lit up when a custom URL is actually in use */
.linkbtn.is-set { color: var(--accent); border-color: var(--accent-dim); }

/* The revealed URL box - spans the three input columns, under its own bet */
.betgrid__url { grid-column: 2 / -1; }

/* ─── Calculated outcomes readout ─────────────────────────────────────── */
/*
   Two groups, not three rows. The first holds the two ordinary results - the
   cost of holding the position - and the second holds the early payout that
   is the reason for holding it. Presented as three equal rows it reads as
   "two losses and a win", which is the wrong story.

   Every line's space is reserved, so the block is a constant height and the
   fields below it never jump while you type.
*/

.calc {
  border-left: 2px solid var(--line);
  padding: .1rem 0 .1rem .75rem;
  margin-bottom: 1rem;
  font-size: .82rem;
}

.calc__group { margin-bottom: .55rem; }

.calc__head {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  padding-bottom: .15rem;
  margin-bottom: .2rem;

  /* Fixed, so a summary that appears or disappears can't nudge the block */
  height: 1.4rem;
  line-height: 1.15rem;
  border-bottom: 1px solid var(--line-soft);
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.calc__head > :first-child { flex: 1; }

.calc__sum {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  text-transform: none;
  font-size: .74rem;
  font-weight: 400;
  color: var(--text-dim);
}

.calc__row {
  display: flex;
  align-items: baseline;
  gap: .6rem;
}

.calc__label {
  flex: 1;
  color: var(--text-dim);
  font-size: .78rem;
}

/* Figures right-aligned in one column, so they can be read down the page */
.calc__value {
  font-variant-numeric: tabular-nums;
  min-width: 5rem;
  text-align: right;
}

.calc__value--ok  { color: var(--accent); }
.calc__value--bad { color: var(--bad); }

/* A cost that is expected. Red is kept for figures that need a second look. */
.calc__value--cost { color: var(--text-dim); }

/* Exactly one line, always. Bigger figures make these strings longer, and a
   note that wraps to two lines would push everything below it down - so they
   are clipped instead, with the full text on the tooltip. */
.calc__note {
  color: var(--text-faint);
  font-size: .72rem;
  height: 1.1rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.calc__foot {
  color: var(--text-faint);
  font-size: .76rem;
  margin-top: .1rem;
  height: 1.2rem;          /* one line - warnings only, and they stay short */
  overflow: hidden;
}

/* Flags a genuine arb - no losing outcome, so liability is meaningless */
.calc--arb { border-left-color: var(--accent-dim); }

/* Flags something worth a second look before sending */
.calc--warn { border-left-color: var(--warn); }
.calc--warn .calc__foot { color: var(--warn); }

/* ─── Channel picker ──────────────────────────────────────────────────────
   One card per channel, nothing selected until you pick. Real radios do the
   work - keyboard arrows and screen readers come free - with the card as
   the label and the input itself hidden.                                    */

/* One row, always. More channels than fit just scroll sideways rather than
   wrapping onto a second line and pushing the form down. */
.channels {
  display: flex;
  gap: .5rem;
  overflow-x: auto;
  padding-bottom: .4rem;
  margin-bottom: .1rem;
  scrollbar-width: thin;
}

.channels__label {
  display: block;
  margin-bottom: .35rem;
  font-size: .78rem;
  color: var(--text-dim);
}

.chancard {
  flex: 0 0 auto;              /* never shrink - scroll the row instead */
  padding: .45rem .9rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  white-space: nowrap;
}

.chancard:hover { border-color: var(--text-faint); }

.chancard input { position: absolute; opacity: 0; pointer-events: none; }

.chancard__name {
  font-size: .875rem;
  color: var(--text-dim);
}

/* Chosen */
.chancard:has(input:checked) {
  border-color: var(--accent-dim);
  background: var(--accent-wash);
}

.chancard:has(input:checked) .chancard__name {
  color: var(--accent);
  font-weight: 600;
}

/* Keyboard focus needs to be visible even though the input isn't */
.chancard:has(input:focus-visible) { outline: 2px solid var(--accent-dim); outline-offset: 2px; }

/* Fallback for browsers without :has() - the class is set by the script */
.chancard.is-picked {
  border-color: var(--accent-dim);
  background: var(--accent-wash);
}

.chancard.is-picked .chancard__name { color: var(--accent); font-weight: 600; }


/* ─── Two-column send form ────────────────────────────────────────────────
   Everything you type on the left, everything worked out from it on the
   right. The right column sticks, so the outcomes stay on screen while you
   work down the form.                                                       */

.sendgrid {
  display: grid;
  /* The results column gives up width first, so the bet grid on the left
     keeps enough room for its four columns on mid-size screens. */
  grid-template-columns: minmax(0, 1fr) minmax(21rem, 26rem);
  gap: 2.5rem;
  align-items: start;       /* required, or the sticky child stretches full height */
}

.sendgrid__inputs { min-width: 0; }

.sendgrid__results {
  position: sticky;
  top: 2rem;
  min-width: 0;
}

/* Nudge the readout down so it lines up with the first field opposite */
.sendgrid__results .calc { margin-top: 1.6rem; }

/* Each working sits on its own line under the row it explains, indented just
   enough to read as a sub-line - any further and it gets clipped in this
   column. */
.sendgrid__results .calc__note { padding-left: .9rem; }

/* ─── Confirmation dialog ─────────────────────────────────────────────────
   Shown before a send goes out. Two panes: the literal request body on the
   left, the same thing rendered as Discord will show it on the right.        */

.modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: 2rem 1.25rem;
}

.modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .65);
}

.modal__card {
  position: relative;
  width: 100%;
  max-width: 60rem;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0,0,0,.55);
}

.modal__head {
  display: flex;
  align-items: baseline;
  gap: .9rem;
  padding: 1rem 1.15rem;
  border-bottom: 1px solid var(--line);
}

.modal__head h2 { font-size: 1rem; }
.modal__head > .btn { margin-left: auto; }

/* Risk rating, chosen in the dialog. Same card pattern as the channels. */
.ratings {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: .5rem;
  padding: 1rem 1.15rem 0;
}

.ratecard {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .55rem .7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
}

.ratecard:hover { border-color: var(--text-faint); }
.ratecard input { position: absolute; opacity: 0; pointer-events: none; }

/* The dot is the colour the embed's bar will actually be */
.ratecard__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex: 0 0 10px;
}

.ratecard[data-tone="none"]  .ratecard__dot { background: #ffffff; }
.ratecard[data-tone="green"] .ratecard__dot { background: #00ff00; }
.ratecard[data-tone="gold"]  .ratecard__dot { background: #ffcc33; }
.ratecard[data-tone="pink"]  .ratecard__dot { background: #ff4d6d; }

.ratecard__text { min-width: 0; }
.ratecard__name { display: block; font-size: .82rem; color: var(--text-dim); }
.ratecard__sub  { display: block; font-size: .68rem; color: var(--text-faint); }

.ratecard.is-picked { background: rgba(255,255,255,.08); }
.ratecard.is-picked .ratecard__name { color: var(--text); font-weight: 600; }

.ratecard[data-tone="green"].is-picked { border-color: #00ff00; }
.ratecard[data-tone="gold"].is-picked  { border-color: #ffcc33; }
.ratecard[data-tone="pink"].is-picked  { border-color: #ff4d6d; }
.ratecard[data-tone="none"].is-picked  { border-color: #ffffff; }

.ratecard:has(input:focus-visible) { outline: 2px solid var(--accent-dim); outline-offset: 2px; }

.modal__body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
  padding: 1.15rem;
  overflow-y: auto;
}

/* Shown in both panes until a rating has been chosen */
.modal__waiting {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--text-faint);
  font-size: .85rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
}

.modal__pane { min-width: 0; }

.modal__panetitle {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.modal__panesub { font-size: .74rem; color: var(--text-faint); margin-bottom: .6rem; }

.modal__json {
  margin: 0;
  padding: .8rem;
  background: var(--bg-input);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: .74rem;
  line-height: 1.5;
  overflow: auto;
  max-height: 24rem;

  /* The description is one very long line. Wrapping it means you can read the
     whole body without scrolling sideways, which is the point of showing it. */
  white-space: pre-wrap;
  word-break: break-word;
}

.modal__foot {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .9rem 1.15rem;
  border-top: 1px solid var(--line);
}

.modal__spacer { flex: 1; }

/* A small yes/no dialog rather than the full two-pane one */
.modal__card--sm { max-width: 27rem; }

.modal__ask {
  padding: 1.1rem 1.25rem;
  font-size: .85rem;
  line-height: 1.6;
  color: var(--text-dim);
}

.modal__ask strong { color: var(--text); }


/* Sits under the preview, outside the embed - context, not message content */
.modal__recap {
  margin-top: .8rem;
  font-size: .74rem;
  line-height: 1.5;
  color: var(--text-faint);
}

.modal__recap strong { color: var(--text-dim); font-weight: 600; }


/* ─── The Discord-ish preview ─────────────────────────────────────────── */

.embed {
  border-left: 3px solid var(--accent);
  border-radius: 3px;
  background: var(--bg-input);
  padding: .8rem .9rem;
  font-size: .84rem;
}

.embed__title { font-weight: 600; margin-bottom: .5rem; }
.embed__rating { font-size: 1.05rem; font-weight: 600; margin-bottom: .3rem; }
.embed__event { font-size: .95rem; margin-bottom: .15rem; }
.embed__market { color: var(--text-dim); margin-bottom: .7rem; }

.embed__stake {
  border-left: 2px solid var(--line);
  padding-left: .6rem;
  margin-bottom: .35rem;
}

.embed__label { color: var(--text-faint); font-size: .74rem; }
.embed__wins { margin-top: .7rem; font-size: .74rem; color: var(--text-faint); }
.embed__figures { font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.embed__figures .up   { color: var(--accent); }
.embed__figures .down { color: var(--bad); }

.embed__image {
  margin-top: .7rem;
  padding: .45rem .6rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  font-size: .76rem;
  color: var(--text-faint);
}

.embed__foot { margin-top: .7rem; font-size: .72rem; color: var(--text-faint); }

@media (max-width: 820px) {
  .modal__body { grid-template-columns: 1fr; }
  .modal__json { max-height: 14rem; }
}


/* ─── Tabs ────────────────────────────────────────────────────────────── */
/*  Used on the Log to switch between outbound and inbound. Underline only. */

.tabs {
  display: flex;
  gap: 1.4rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: 1.5rem;
}

.tab {
  padding: 0 0 .6rem;
  color: var(--text-dim);
  font-size: .875rem;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.tab:hover { color: var(--text); text-decoration: none; }
.tab.is-active { color: var(--text); border-bottom-color: var(--accent); }


/* ─── Odds Feed ───────────────────────────────────────────────────────── */

/* The controls that decide what a pull asks for */
.pullbar {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: flex-start;
  padding-bottom: 1.5rem;
}

.pullbar .field { margin-bottom: 0; min-width: 11rem; }
.pullbar .field:last-child { min-width: 0; padding-top: 1.35rem; }

/* One match. <details> does the expanding, no JS needed for it. */
.oddscard {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin-bottom: .5rem;
}

/* A match with a back/lay arb gets a green edge */
.oddscard--arb { border-left: 2px solid var(--accent-dim); }

.oddscard__head {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .7rem .9rem;
  cursor: pointer;
  list-style: none;
}

.oddscard__head::-webkit-details-marker { display: none; }
.oddscard__head:hover { background: rgba(255,255,255,.05); }

.oddscard__teams { flex: 1; min-width: 0; }
.oddscard__title { font-size: .95rem; font-weight: 500; }

.oddscard__meta {
  font-size: .76rem;
  color: var(--text-faint);
  display: flex;
  align-items: center;
  gap: .45rem;
  margin-top: .1rem;
}

/* Best back price per outcome, shown without expanding */
.oddscard__bests { display: flex; gap: 1.1rem; flex: 0 0 auto; }

.oddscard__best { text-align: right; min-width: 3.6rem; }

.oddscard__bestlabel {
  font-size: .66rem;
  color: var(--text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 6.5rem;
}

.oddscard__bestval { font-size: .95rem; font-variant-numeric: tabular-nums; }

.oddscard__body {
  padding: .2rem .9rem 1rem;
  border-top: 1px solid var(--line-soft);
}

/* Marks an exchange in the book column */
.exchtag {
  font-size: .6rem;
  font-weight: 600;
  letter-spacing: .06em;
  color: var(--accent);
  border: 1px solid var(--accent-dim);
  border-radius: 3px;
  padding: 0 .2rem;
}

/* The lay row sits under its exchange's back row */
.layrow td { color: var(--text-faint); }

td.right, th.right { text-align: right; }

/* Best available price in each column */
td.is-best    { color: var(--accent); font-weight: 600; }
td.is-bestlay { color: var(--warn); }

.arbnote {
  padding: .6rem .8rem;
  margin: .8rem 0;
  border-left: 2px solid var(--accent-dim);
  background: var(--accent-wash);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: .82rem;
}

textarea#rawJson {
  font-size: .76rem;
  line-height: 1.5;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}

@media (max-width: 700px) {
  /* The per-outcome prices in the header don't fit next to the teams */
  .oddscard__bests { display: none; }
}

/* ─── Send row ────────────────────────────────────────────────────────── */

.sendrow {
  display: flex;
  align-items: center;
  gap: .9rem;
  flex-wrap: wrap;
  padding-top: .25rem;
}

/* Chosen-image preview */
.preview {
  margin-top: .7rem;
  display: flex;
  gap: .8rem;
  align-items: center;
}

.preview img {
  max-width: 90px;
  max-height: 64px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  display: block;
}

.preview__meta { min-width: 0; font-size: .78rem; }
.preview__name { word-break: break-all; }


/* ─── Sportscheck ─────────────────────────────────────────────────────────
   Two columns, roughly 35 / 65. The left one is a bordered box because it is
   a stored snapshot rather than live page content - the only other boxed
   things in here are the modal and the embed preview. */

.checkgrid {
  display: grid;
  grid-template-columns: 35fr 65fr;
  gap: 2rem;
  align-items: start;
}

.checkgrid__left,
.checkgrid__right { min-width: 0; }

/* The left column stays put while the right one scrolls with the page. It is
   never taller than the viewport, so it can't be cut off half way down - the
   competition list inside it takes whatever height is left over and scrolls
   on its own. */
.checkgrid__left {
  position: sticky;
  top: 1.25rem;
  max-height: calc(100vh - 2.5rem);
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* The first block sits level with the top of the box on the left */
.checkgrid__right .block:first-child { border-top: 0; padding-top: 0; }

.sportbox {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem;

  /* Head, totals, tools and foot keep their size; the list absorbs the rest */
  display: flex;
  flex-direction: column;
  min-height: 0;
  max-height: 100%;
}

.sportbox > *:not(.sportbox__list) { flex: 0 0 auto; }

.sportbox__head {
  display: flex;
  align-items: flex-start;
  gap: .8rem;
  margin-bottom: .9rem;
}

.sportbox__title { flex: 1; min-width: 0; }
.sportbox__title h2 { font-size: .9rem; font-weight: 600; }

.sportbox__stamp {
  margin-top: .2rem;
  font-size: .74rem;
  color: var(--text-faint);
}

.sportbox__totals {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  padding-bottom: .8rem;
  border-bottom: 1px solid var(--line-soft);
  font-size: .8rem;
  color: var(--text-dim);
}

.sportbox__totals strong { color: var(--accent); font-variant-numeric: tabular-nums; }

.sportbox__tools {
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .8rem 0;
}

.sportbox__tools input[type="search"] {
  flex: 1;
  min-width: 0;
  margin: 0;
}

.toggle {
  display: flex;
  align-items: center;
  gap: .35rem;
  flex: 0 0 auto;
  font-size: .76rem;
  color: var(--text-dim);
  white-space: nowrap;
  cursor: pointer;
}

.toggle input { width: auto; margin: 0; }

/* Fixed height so the right-hand column doesn't jump around as you filter */
.sportbox__list {
  flex: 1 1 auto;
  min-height: 6rem;
  overflow-y: auto;
  margin-right: -.4rem;
  padding-right: .4rem;
}

.sportgroup { margin-bottom: .9rem; }
.sportgroup:last-child { margin-bottom: 0; }

.sportgroup__head {
  display: flex;
  gap: .6rem;
  align-items: baseline;
  padding: .3rem 0;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
  border-bottom: 1px solid var(--line-soft);
}

.sportgroup__head > :first-child { flex: 1; }

.sportrow {
  display: flex;
  align-items: center;
  gap: .55rem;
  width: 100%;
  padding: .4rem .35rem;
  font: inherit;
  text-align: left;
  color: var(--text);
  background: transparent;
  border: 0;
  border-radius: var(--radius);
  cursor: pointer;
}

/* display:flex above beats the browser's default [hidden] rule, so say it */
.sportrow[hidden] { display: none; }

.sportrow:hover { background: rgba(255,255,255,.06); }
.sportrow:focus-visible { outline: 2px solid var(--accent-dim); outline-offset: -2px; }

.sportrow.is-picked { background: var(--accent-wash); }
.sportrow.is-picked .sportrow__title { color: var(--accent); font-weight: 600; }

.sportrow__dot {
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-radius: 50%;
  background: #4ade80;
}

.sportrow.is-off .sportrow__dot { background: var(--line); }
.sportrow.is-off .sportrow__title { color: var(--text-dim); }

.sportrow__text { flex: 1; min-width: 0; }

.sportrow__title {
  display: block;
  font-size: .84rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sportrow__key {
  display: block;
  font-family: var(--mono);
  font-size: .68rem;
  color: var(--text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sportrow__tag {
  flex: 0 0 auto;
  font-size: .64rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.sportbox__foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .6rem;
  margin-top: .9rem;
  padding-top: .8rem;
  border-top: 1px solid var(--line-soft);
}

/* ─── Bet365: the competition picker ──────────────────────────────────── */

.comp__country {
  padding: .45rem 0 .25rem;
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
  border-bottom: 1px solid var(--line-soft);
}

.comprow {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .4rem .35rem;
  cursor: pointer;
  border-radius: var(--radius);
}

.comprow:hover { background: rgba(255,255,255,.05); }
.comprow[hidden] { display: none; }

.comprow input { width: auto; margin: 0; flex: 0 0 auto; }

.comprow__text { flex: 1; min-width: 0; }

.comprow__name {
  display: block;
  font-size: .82rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.comprow__key {
  display: block;
  font-family: var(--mono);
  font-size: .64rem;
  color: var(--text-faint);
}

.comprow__count {
  flex: 0 0 auto;
  font-size: .72rem;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.comprow:has(input:checked) .comprow__name { color: var(--accent); font-weight: 600; }


/* ─── How old a stored pull is ─────────────────────────────────────────────
   One scale, used by the dot beside each competition, the little line under
   its name, and the banner on the right. They can't disagree because they
   all read data-band, and data-band is set in one place. */

[data-band="fresh"] { --band: var(--accent); }
[data-band="ok"]    { --band: var(--accent-dim); }
[data-band="aging"] { --band: var(--warn); }
[data-band="stale"] { --band: var(--bad); }
[data-band="never"] { --band: var(--line); }

.sportrow__dot[data-band] { background: var(--band); }
.sportrow__dot[data-band="never"] { background: var(--line); }

.sportrow__key[data-band] { color: var(--text-faint); }
.sportrow__key[data-band="aging"] { color: var(--warn); }
.sportrow__key[data-band="stale"] { color: var(--bad); }

/* The line the page hangs off: where these numbers came from, and how old */

.asof {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem;
  margin: .9rem 0 .2rem;
  padding: .7rem .85rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--band, var(--line));
  border-radius: var(--radius);
  background: var(--bg-input);
  font-size: .82rem;
}

.asof__lead { color: var(--text); }
.asof__lead strong { font-weight: 600; }

.asof__age {
  padding: .05rem .45rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--band, var(--line)) 22%, transparent);
  color: var(--text);
  font-size: .72rem;
  white-space: nowrap;
}

.asof__note {
  flex: 1 1 100%;
  font-size: .74rem;
  color: var(--text-faint);
}

.asof__note a { color: var(--text-dim); }

.asof[data-band="stale"] .asof__lead,
.asof[data-band="never"] .asof__lead { color: var(--warn); }


/* ─── The picked competition, on the right ────────────────────────────── */

.pickhead {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding-bottom: .9rem;
  border-bottom: 1px solid var(--line-soft);
}

.pickhead__main { flex: 1; min-width: 0; }

.pickhead__title { font-size: 1rem; font-weight: 600; }

.pickhead__meta {
  margin-top: .15rem;
  font-size: .78rem;
  color: var(--text-dim);
}

.pickhead__meta code { color: var(--accent); }
.pickhead__sep { color: var(--text-faint); margin: 0 .2rem; }

/* The two calls */

.pullrow {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 1.1rem;
  padding: .9rem 0;
}

.pullrow__field { min-width: 12rem; }

.pullrow__field > span {
  display: block;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: .25rem;
}

.pullrow__field select { margin: 0; }

.pullrow__act { display: flex; flex-direction: column; gap: .25rem; }

.pullrow__cost { font-size: .7rem; color: var(--text-faint); }

/* When each side was last pulled */

.stamps {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .4rem;
  padding: .6rem 0 1rem;
  font-size: .76rem;
  color: var(--text-dim);
  border-bottom: 1px solid var(--line-soft);
}

.stamps__sep { color: var(--text-faint); }

/* ─── One match ───────────────────────────────────────────────────────── */

.match { border-bottom: 1px solid var(--line-soft); }

.match__head {
  display: flex;
  align-items: baseline;
  gap: .9rem;
  padding: .6rem .35rem;
  cursor: pointer;
  list-style: none;
}

.match__head::-webkit-details-marker { display: none; }
.match__head:hover { background: rgba(255,255,255,.05); }
.match[open] .match__head { background: rgba(255,255,255,.04); }

.match__when {
  flex: 0 0 10.5rem;
  font-size: .76rem;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.match__teams { flex: 1; min-width: 0; font-size: .88rem; }

.match__prices { display: flex; gap: .45rem; flex: 0 0 auto; }

.match__best {
  min-width: 2.9rem;
  padding: .05rem .3rem;
  text-align: right;
  font-size: .8rem;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
}

.match__noprice { font-size: .74rem; color: var(--text-faint); }

.match__body { padding: .3rem .35rem 1rem; }

.match__none { font-size: .8rem; color: var(--text-faint); padding: .5rem 0 .2rem; }

.match__table th:first-child, .match__table td:first-child { width: 30%; }

.match__showall { margin-top: .7rem; }

.match__foot {
  display: flex;
  align-items: center;
  gap: .8rem;
  margin-top: .9rem;
  padding-top: .7rem;
  border-top: 1px solid var(--line-soft);
}

.match__spacer { flex: 1; }

/* Price cells */

.odds__book { color: var(--text-dim); }

.odds__tag {
  margin-left: .45rem;
  font-size: .62rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--accent-dim);
}

.match__table tr.is-exchange .odds__book { color: var(--text); }

.odds { font-variant-numeric: tabular-nums; }

.odds__back { display: block; font-size: .85rem; }
.odds__lay  { display: block; font-size: .68rem; color: var(--text-faint); }

/* An exchange row shows its lay price and nothing else — same column, same
   place, different side of the bet, so it gets its own colour. */

.odds__lead {
  display: block;
  font-size: .85rem;
  font-weight: 600;
  color: var(--lay);
}

/* Best of whichever number is shown: highest back, lowest lay */
.odds--best .odds__back { color: var(--accent); font-weight: 600; }
.odds--best .odds__lead { color: var(--lay-best); }

.odds--best.odds--lay {
  background: color-mix(in srgb, var(--lay) 11%, transparent);
  border-radius: var(--radius);
}

tr.is-exchange .odds__tag { color: var(--lay); }


/* ─── Bet365, matched in from the other feed ──────────────────────────────
   A second opinion, so it is kept apart: its own hue, and a rule above and
   below to say it is not part of the block it sits in. */

tr.is-bet365 > * {
  background: color-mix(in srgb, var(--b365) 7%, transparent);
  border-top: 1px solid color-mix(in srgb, var(--b365) 30%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--b365) 30%, transparent);
}

tr.is-bet365 .odds__book { color: var(--text); }

.odds__lead--b365 { color: var(--b365); }
.odds__tag--b365  { color: var(--b365); }

/* The badge on the collapsed row — says so before you open it.

   The slot is a fixed width and is always present, empty or not, so the
   price trio stays in one column all the way down the list instead of
   shifting left on the rows that happen to have a badge. */

.match__flag {
  flex: 0 0 7rem;
  text-align: right;
  white-space: nowrap;
}

.found {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-size: .6rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--b365);
}

/* A dot, not a box — it shouldn't read as a fourth price */
.found::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--b365);
}

/* Hollow dot for an inferred pair */
.found--maybe { opacity: .85; }
.found--maybe::before { background: none; box-shadow: inset 0 0 0 1px var(--b365); }

/* Where the Bet365 numbers came from, under the table */

.xmatch {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem;
  margin-top: .8rem;
  padding: .6rem .75rem;
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--band, var(--b365));
  border-radius: var(--radius);
  font-size: .78rem;
}

.xmatch__lead { color: var(--text-dim); }
.xmatch__lead strong { color: var(--text); font-weight: 600; }

.xmatch__age {
  padding: .05rem .45rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--band, var(--b365)) 22%, transparent);
  font-size: .7rem;
  white-space: nowrap;
}

/* The note wraps to its own line; the button stays up on the first one */
.xmatch__note {
  order: 4;
  flex: 1 1 100%;
  font-size: .72rem;
  color: var(--text-faint);
}

.xmatch__note strong { color: var(--text-dim); font-weight: 500; }
.xmatch__note a { color: var(--text-dim); }

.xmatch__open { order: 3; margin-left: auto; }

.xmatch[data-band="stale"] .xmatch__lead,
.xmatch[data-band="never"] .xmatch__lead { color: var(--warn); }



/* ─── Settings and Profile ────────────────────────────────────────────── */

.setgrid {
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: 1.5rem;
  align-items: start;
}

.setcard {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.1rem 1.1rem;
  min-width: 0;
}

.setcard__head {
  display: flex;
  align-items: baseline;
  gap: .9rem;
  padding-bottom: .7rem;
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: .3rem;
}

.setcard__head h2 { flex: 1; font-size: .9rem; }

.setcard__count { font-size: .76rem; color: var(--text-faint); font-variant-numeric: tabular-nums; }

.setcard__foot { margin: 1rem 0 0; padding-top: .8rem; border-top: 1px solid var(--line-soft); }

.setgroup__head {
  margin-top: .9rem;
  padding: .3rem 0;
  font-size: .66rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.setrow {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .45rem .2rem;
  border-bottom: 1px solid var(--line-soft);
  cursor: pointer;
}

.setrow:last-child { border-bottom: 0; }
.setrow:hover { background: rgba(255,255,255,.04); }

.setrow__text { flex: 1; min-width: 0; }

.setrow__name { display: block; font-size: .85rem; }

.setrow__key {
  display: block;
  font-family: var(--mono);
  font-size: .66rem;
  color: var(--text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Bookmaker tiles. Pale in both states - the tint says connected or not, and
   the grid reads as one block rather than a list you scan down. The corner
   flag is the `connected` value from lib/books.js: 1 or 0. */

.tilegrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
  gap: .5rem;
  margin: .5rem 0 .3rem;
}

.tile {
  position: relative;
  display: block;
  padding: .55rem .6rem .5rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, .04);
  cursor: pointer;
  min-width: 0;
}

.tile:hover { border-color: var(--text-faint); }

.tile input { position: absolute; opacity: 0; pointer-events: none; }

/* The 1 / 0 in the corner is the `connected` value itself */
.tile__flag {
  position: absolute;
  top: .3rem;
  right: .4rem;
  min-width: 1rem;
  text-align: center;
  font-size: .62rem;
  font-variant-numeric: tabular-nums;
  color: var(--text-faint);
  border: 1px solid var(--line-soft);
  border-radius: 2px;
  line-height: 1.1;
}

.tile__name {
  display: block;
  font-size: .82rem;
  color: var(--text-dim);
  padding-right: 1.1rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tile__key {
  display: block;
  font-family: var(--mono);
  font-size: .62rem;
  color: var(--text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* On: the same tile, tinted green rather than grey */
.tile:has(input:checked) {
  background: var(--accent-wash);
  border-color: var(--accent-dim);
}

.tile:has(input:checked) .tile__name { color: var(--accent); font-weight: 600; }
.tile:has(input:checked) .tile__flag {
  color: var(--accent);
  border-color: var(--accent-dim);
}

.tile:has(input:focus-visible) { outline: 2px solid var(--accent-dim); outline-offset: 2px; }


/* The switch itself - a checkbox with the box hidden behind a track */

.switch { position: relative; flex: 0 0 auto; display: block; width: 30px; height: 17px; }

.switch input {
  position: absolute;
  inset: 0;
  margin: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

.switch__track {
  display: block;
  width: 100%;
  height: 100%;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  transition: background .12s, border-color .12s;
  pointer-events: none;
}

.switch__track::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--text-faint);
  transition: transform .12s, background .12s;
}

.switch input:checked + .switch__track {
  background: var(--accent-wash);
  border-color: var(--accent-dim);
}

.switch input:checked + .switch__track::after {
  transform: translateX(13px);
  background: var(--accent);
}

.switch input:focus-visible + .switch__track {
  outline: 2px solid var(--accent-dim);
  outline-offset: 2px;
}

/* Placeholder rows - deliberately inert */

.stub__row {
  display: flex;
  gap: .9rem;
  align-items: baseline;
  padding: .55rem 0;
  border-bottom: 1px solid var(--line-soft);
}

.stub__row:last-child { border-bottom: 0; }

.stub__label {
  flex: 0 0 10rem;
  font-size: .82rem;
  color: var(--text-dim);
}

.stub__note { font-size: .8rem; color: var(--text-faint); }


/* ─── 6. Buttons, badges, notices, toasts ───────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  padding: .45rem .9rem;
  font: inherit;
  font-size: .85rem;
  color: var(--text-dim);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
}

.btn:hover { color: var(--text); border-color: var(--text-faint); text-decoration: none; }

/* The one action per page that matters — outlined in green, not filled */
.btn--primary {
  color: var(--accent);
  border-color: var(--accent-dim);
}

.btn--primary:hover:not(:disabled) {
  color: var(--accent);
  background: var(--accent-wash);
  border-color: var(--accent);
}

.btn--block { width: 100%; }
.btn--sm { padding: .25rem .6rem; font-size: .78rem; }

.btn:disabled { opacity: .35; cursor: not-allowed; }

/* Badges — plain text, colour only */
.badge {
  font-size: .76rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.badge--ok    { color: var(--accent); }
.badge--bad   { color: var(--bad); }
.badge--warn  { color: var(--warn); }
.badge--quiet { color: var(--text-faint); }

/* Notices — a left rule and nothing else */
.notice {
  padding: .1rem 0 .1rem .8rem;
  border-left: 2px solid var(--accent-dim);
  font-size: .85rem;
  color: var(--text-dim);
  margin-bottom: 1.5rem;
}

.notice--warn { border-left-color: var(--warn); }
.notice--bad  { border-left-color: var(--bad); }
.notice > :last-child { margin-bottom: 0; }
.notice strong { color: var(--text); font-weight: 600; }

/* Toasts */
.toasts {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 100;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-width: 340px;
}

.toast {
  padding: .65rem .85rem;
  background: var(--bg-input);
  border: 1px solid var(--line);
  border-left: 2px solid var(--accent-dim);
  border-radius: var(--radius);
  font-size: .82rem;
}

.toast--bad { border-left-color: var(--bad); }

/* Spinner inside the submit button while sending */
.spinner {
  width: 11px;
  height: 11px;
  border: 1.5px solid var(--line);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: spin .6s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }


/* ─── 7. Sign in ────────────────────────────────────────────────────────── */

.auth {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 2rem 1.25rem;
}

.auth__card { width: 100%; max-width: 300px; }
.auth__card h1 { font-size: 1rem; margin-bottom: 1.25rem; }


/* ─── 8. Small screens ──────────────────────────────────────────────────── */

/* Two columns need roughly 1150px once the sidebar has taken its 200px.
   Below that, stack them and stop the results column sticking. */
@media (max-width: 1150px) {
  .sendgrid { grid-template-columns: 1fr; gap: 1.5rem; }
  .sendgrid__results { position: static; }
  .sendgrid__results .calc { margin-top: 0; }

  .checkgrid { grid-template-columns: 1fr; gap: 1.5rem; }
  .setgrid   { grid-template-columns: 1fr; gap: 1.5rem; }

  /* Stacked, there is nothing to stick to - the box goes back to normal flow
     and the list gets a plain height cap instead of the viewport. */
  .checkgrid__left {
    position: static;
    max-height: none;
    display: block;
  }

  .checkgrid__left .sportbox { max-height: none; }
  .sportbox__list { max-height: 26rem; }

  .checkgrid__right .block:first-child {
    border-top: 1px solid var(--line);
    padding-top: 1.5rem;
  }
}

@media (max-width: 800px) {
  .shell { grid-template-columns: 1fr; }

  .sidebar {
    position: static;
    height: auto;
    border-right: 0;
    border-bottom: 1px solid var(--line);
  }

  .sidebar__nav { padding: .5rem; }

  /* Nav turns into a horizontal scroller */
  .sidebar__nav ul {
    display: flex;
    gap: .15rem;
    overflow-x: auto;
  }

  .navlink { white-space: nowrap; border-left: 0; border-bottom: 2px solid transparent; }
  .navlink.is-active { border-bottom-color: var(--accent); }
  .sidebar__section { display: none; }

  .content { padding: 1.5rem 1.25rem 3rem; }
  .stats { gap: 1.5rem; }

  /* The four-column bet grid doesn't fit a phone. Drop the shared column
     headings and stack each bet: side label, then the select, then stake and
     odds side by side. The inputs keep their aria-labels and placeholders. */
  .betgrid { grid-template-columns: 1fr 1fr; gap: .5rem; }
  .betgrid__col { display: none; }

  .betgrid__side {
    grid-column: 1 / -1;
    margin-top: .4rem;
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--text-faint);
  }

  .betgrid__pick { grid-column: 1 / -1; }
  .betgrid__url  { grid-column: 1 / -1; }

  .calc__row { flex-wrap: wrap; }
  .calc__note { flex: 1 1 100%; }
}

@media print {
  .sidebar, .filters { display: none; }
}
