/* Sportfolio. One stylesheet, no build step, no url() — a url() that can't be
   resolved fails collectstatic, which fails the Railway build before the
   deploy ever starts. Icons are inline SVG in the templates; the favicon is a
   data: URI in base.html. System fonts only. */

/* ---------------------------------------------------------------- tokens - */

:root {
  color-scheme: dark;

  /* surfaces */
  --bg: #0b0d10;
  --panel: #14171d;
  --panel-2: #1b1f27;
  --line: #242935;
  --line-soft: #1b1f27;

  /* ink */
  --text: #e8eaf0;
  --muted: #8b93a7;
  --faint: #5c6478;

  /* semantics. accent is the up-green: this is a market, and the brand colour
     and the gain colour being the same thing is the point. */
  --up: #00d68f;
  --up-bg: rgba(0, 214, 143, 0.12);
  --down: #ff5a5f;
  --down-bg: rgba(255, 90, 95, 0.12);
  --flat: #8b93a7;
  --accent: #00d68f;
  --accent-ink: #04120c;
  --warn: #fbbf24;
  --warn-bg: rgba(251, 191, 36, 0.12);

  /* type: 1.25 ratio off a 15px root */
  --t-hero: 2.75rem;
  --t-xl: 1.75rem;
  --t-lg: 1.25rem;
  --t-md: 1rem;
  --t-sm: 0.875rem;
  --t-xs: 0.75rem;
  --lh-tight: 1.05;
  --w-med: 520;
  --w-semi: 620;
  --w-bold: 700;
  --ff: ui-sans-serif, -apple-system, "Segoe UI", system-ui, sans-serif;
  --ff-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

  /* space: 4px base */
  --s1: 0.25rem;
  --s2: 0.5rem;
  --s3: 0.75rem;
  --s4: 1rem;
  --s5: 1.5rem;
  --s6: 2rem;
  --s7: 3rem;
  --s8: 4rem;

  /* radii */
  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 16px;
  --r-pill: 999px;

  /* elevation */
  --e1: 0 1px 2px rgba(0, 0, 0, 0.35);
  --e2: 0 8px 24px -8px rgba(0, 0, 0, 0.55);
  --ring: 0 0 0 3px color-mix(in srgb, var(--accent) 35%, transparent);

  /* layout */
  --page: 1080px;
  --header-h: 56px;
  --tabbar-h: 58px;
  --dur: 0.15s;
}

@media (prefers-color-scheme: light) {
  :root {
    color-scheme: light;
    --bg: #f7f8fa;
    --panel: #ffffff;
    --panel-2: #f2f4f7;
    --line: #e3e6ec;
    --line-soft: #eef0f4;
    --text: #0f1218;
    --muted: #5d6579;
    --faint: #98a0b3;
    --up: #00875a;
    --up-bg: rgba(0, 135, 90, 0.10);
    --down: #c2333a;
    --down-bg: rgba(194, 51, 58, 0.10);
    --flat: #5d6579;
    --accent: #00875a;
    --accent-ink: #ffffff;
    --warn: #a16207;
    --warn-bg: rgba(161, 98, 7, 0.10);
    --e1: 0 1px 2px rgba(16, 24, 40, 0.06);
    --e2: 0 8px 24px -8px rgba(16, 24, 40, 0.16);
  }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ------------------------------------------------------------------ base - */

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.5 var(--ff);
  /* every price on the page, not just the ones inside tables */
  font-variant-numeric: tabular-nums;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
}

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

:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-radius: var(--r-sm);
}

h1, h2, h3 { letter-spacing: -0.02em; font-weight: var(--w-semi); }
h1 { font-size: var(--t-xl); margin: 0 0 var(--s1); }
h2 { font-size: var(--t-lg); margin: 0 0 var(--s2); }
h3 { font-size: var(--t-md); margin: 0 0 var(--s3); }

.sub { color: var(--muted); margin: 0 0 var(--s5); font-size: var(--t-sm); }
.muted { color: var(--muted); }
.faint { color: var(--faint); }
.up { color: var(--up); }
.down { color: var(--down); }
.flat { color: var(--muted); }
.num { font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }

/* ---------------------------------------------------------------- layout - */

.shell { min-height: 100dvh; display: flex; flex-direction: column; }

main {
  width: 100%;
  max-width: var(--page);
  margin: 0 auto;
  padding: var(--s5) var(--s4);
  flex: 1;
}

/* room for the fixed bottom tab bar on phones */
@media (max-width: 719px) {
  main { padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + var(--s5)); }
}

.stack > * + * { margin-top: var(--s4); }

/* ---------------------------------------------------------------- header - */

.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: var(--s4);
  height: var(--header-h);
  padding: 0 var(--s4);
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--line);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-weight: var(--w-bold);
  letter-spacing: -0.03em;
  font-size: var(--t-md);
  color: var(--text);
}
.brand:hover { text-decoration: none; }
.brand svg { display: block; color: var(--accent); }

.league-pill {
  font-size: var(--t-xs);
  color: var(--muted);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  padding: 3px var(--s2);
  /* The full name, never an ellipsis — it is the one label that says where
     you are, and the switcher's trigger has to name what it switches. */
  white-space: nowrap;
}

.topnav { display: none; gap: var(--s1); margin-left: var(--s2); }
.topnav a {
  color: var(--muted);
  font-size: var(--t-sm);
  font-weight: var(--w-med);
  padding: var(--s2) var(--s3);
  border-radius: var(--r-sm);
}
.topnav a:hover { color: var(--text); background: var(--panel-2); text-decoration: none; }
.topnav a[aria-current="page"] { color: var(--text); background: var(--panel-2); }

@media (min-width: 720px) { .topnav { display: flex; } }

.topbar .spacer { margin-left: auto; }

.buying-power {
  text-align: right;
  line-height: 1.15;
  white-space: nowrap;
}
.buying-power .label { display: block; font-size: 10px; color: var(--faint); text-transform: uppercase; letter-spacing: 0.06em; }
.buying-power .value { font-size: var(--t-sm); font-weight: var(--w-semi); }
.buying-power .reserved { display: block; font-size: 10px; color: var(--faint); }

/* zero-JS account dropdown */
.acct { position: relative; }
.acct > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--r-pill);
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: var(--t-xs);
  font-weight: var(--w-semi);
  text-transform: uppercase;
}
.acct > summary::-webkit-details-marker { display: none; }
.acct > summary:hover { color: var(--text); }
.acct-menu {
  position: absolute;
  right: 0;
  top: calc(100% + var(--s2));
  min-width: 190px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--e2);
  padding: var(--s2);
  z-index: 40;
}
.acct-menu .who { padding: var(--s2) var(--s3); border-bottom: 1px solid var(--line); margin-bottom: var(--s2); }
.acct-menu .who strong { display: block; font-weight: var(--w-semi); }
.acct-menu .who span { font-size: var(--t-xs); color: var(--faint); }
.acct-menu a, .acct-menu button {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--s2) var(--s3);
  border-radius: var(--r-sm);
  color: var(--text);
  font-size: var(--t-sm);
  background: none;
  border: 0;
  margin: 0;
  cursor: pointer;
  font: inherit;
}
.acct-menu a:hover, .acct-menu button:hover { background: var(--panel-2); text-decoration: none; }

/* zero-JS league switcher — the pill becomes the trigger when there is a choice */
.league-menu { position: relative; }
.league-menu > summary { list-style: none; cursor: pointer; display: inline-block; }
.league-menu > summary::-webkit-details-marker { display: none; }
.league-menu > summary.league-pill::after { content: " ▾"; color: var(--faint); font-size: 1.35em; line-height: 1; vertical-align: -0.1em; }
.league-menu > summary:hover { color: var(--text); }
.league-menu .acct-menu { left: 0; right: auto; }
.league-menu .acct-menu a[aria-current] { color: var(--accent); }

/* --------------------------------------------------------------- tab bar - */

.tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 30;
  display: flex;
  height: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  background: color-mix(in srgb, var(--panel) 94%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  border-top: 1px solid var(--line);
}
.tabbar a {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  color: var(--faint);
  font-size: 10px;
  font-weight: var(--w-med);
  letter-spacing: 0.02em;
}
.tabbar a:hover { text-decoration: none; }
.tabbar a[aria-current="page"] { color: var(--accent); }
.tabbar svg { display: block; }

@media (min-width: 720px) { .tabbar { display: none; } }

/* --------------------------------------------------------------- cadence - */

/* The design thesis, made structural: this market clears once a night, and
   the UI should say so on every page rather than implying a ticking price. */
.cadence {
  display: flex;
  align-items: center;
  gap: var(--s2);
  justify-content: center;
  flex-wrap: wrap;
  padding: var(--s2) var(--s4);
  font-size: var(--t-xs);
  color: var(--faint);
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}
.cadence .dot {
  width: 6px; height: 6px;
  border-radius: var(--r-pill);
  background: var(--up);
  flex: none;
}
.cadence strong { color: var(--muted); font-weight: var(--w-med); }

/* The IPO strip says a different thing than the nightly one — a market that
   has not opened yet, not one that cleared a few hours ago — so it does not
   borrow the green dot that means "trading". */
.cadence.ipo { background: var(--warn-bg); color: var(--muted); }
.cadence.ipo .dot { background: var(--warn); }
.cadence.ipo strong { color: var(--text); }

/* ---------------------------------------------------------------- panels - */

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s4) var(--s5);
}
.panel + .panel { margin-top: var(--s4); }
.panel > h3:first-child { margin-top: 0; }
.panel-flush { padding: var(--s2) 0; }
.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s3);
}
.panel-head h3 { margin: 0; }
.panel-head .more { font-size: var(--t-xs); color: var(--muted); }

.grid { display: grid; gap: var(--s4); grid-template-columns: 1fr; }
@media (min-width: 900px) {
  .grid { grid-template-columns: minmax(0, 1fr) 340px; align-items: start; }
  .grid > .rail { position: sticky; top: calc(var(--header-h) + var(--s4)); }
}

/* ------------------------------------------------------------------ hero - */

.hero { margin-bottom: var(--s5); }
.hero .eyebrow {
  font-size: var(--t-xs);
  color: var(--faint);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 0 0 var(--s2);
}
.hero .value {
  font-size: var(--t-hero);
  line-height: var(--lh-tight);
  font-weight: var(--w-bold);
  letter-spacing: -0.035em;
  margin: 0;
}
.hero .delta {
  margin: var(--s2) 0 0;
  font-size: var(--t-sm);
  font-weight: var(--w-med);
}
.hero .delta .since { color: var(--faint); font-weight: 400; }

/* -------------------------------------------------------- the row primitive */

/* One list row serves market, holdings, orders, fills and standings. Mobile
   layout is the base layout; wide columns appear at 900px. */
.rows { display: flex; flex-direction: column; }
.row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s3);
  min-height: 56px;
  padding: var(--s3) var(--s2);
  border-bottom: 1px solid var(--line-soft);
  color: var(--text);
}
a.row:hover { text-decoration: none; background: var(--panel-2); }
a.row:active { background: var(--line); }
.row:last-child { border-bottom: 0; }

.row-main { min-width: 0; }
.row-title {
  font-size: var(--t-md);
  font-weight: var(--w-med);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.row-meta {
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
  font-size: var(--t-xs);
  color: var(--faint);
  margin-top: 2px;
}
.row-side { text-align: right; white-space: nowrap; }
.row-value { font-size: var(--t-md); font-weight: var(--w-semi); }
.row-delta { font-size: var(--t-sm); margin-top: 2px; }

.row-spark { display: none; width: 80px; height: 24px; flex: none; }
.row-wide { display: none; text-align: right; font-size: var(--t-sm); color: var(--muted); min-width: 84px; }

/* Only the market list carries sparklines and the extra columns. Everything
   else stays two-column at every size, so a row without them doesn't land its
   value cell in a column meant for something else. */
@media (min-width: 620px) {
  .rows.market .row { grid-template-columns: minmax(0, 1fr) 80px auto; }
  .rows.market .row-spark { display: block; }
}
@media (min-width: 900px) {
  .rows.market .row { grid-template-columns: minmax(0, 1fr) repeat(3, 84px) 80px auto; }
  .rows.market .row-wide { display: block; }
}

/* Sort header. Same grid as a row, so the cells stay aligned with the columns
   they label and disappear with them at each breakpoint. */
.row.head {
  min-height: 0;
  padding-top: var(--s2);
  padding-bottom: var(--s2);
  border-bottom: 1px solid var(--line);
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.row.head:hover { background: none; }
.row.head a { color: var(--faint); font-weight: var(--w-med); }
.row.head a:hover { color: var(--text); text-decoration: none; }
.row.head a[aria-current] { color: var(--accent); }

.row-empty {
  padding: var(--s7) var(--s4);
  text-align: center;
  color: var(--muted);
  font-size: var(--t-sm);
}

/* ----------------------------------------------------------------- chips - */

.tag {
  display: inline-block;
  font-size: var(--t-xs);
  line-height: 1.4;
  padding: 1px var(--s2);
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  color: var(--muted);
  white-space: nowrap;
}
.tag.locked { color: var(--down); border-color: color-mix(in srgb, var(--down) 45%, transparent); background: var(--down-bg); }
.tag.bye { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, transparent); background: var(--warn-bg); }
.tag.held { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, transparent); background: var(--up-bg); }
.tag.buy { color: var(--up); border-color: color-mix(in srgb, var(--up) 45%, transparent); }
.tag.sell { color: var(--down); border-color: color-mix(in srgb, var(--down) 45%, transparent); }

/* filter pills — plain GET links, no JS */
.pills { display: flex; gap: var(--s2); flex-wrap: wrap; }
.pills a {
  font-size: var(--t-sm);
  font-weight: var(--w-med);
  color: var(--muted);
  padding: var(--s1) var(--s3);
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--panel);
}
.pills a:hover { color: var(--text); text-decoration: none; border-color: var(--muted); }
.pills a[aria-current] {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: var(--accent);
}

/* ------------------------------------------------------------- stat lines - */

.stat {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s3);
  padding: var(--s2) 0;
  font-size: var(--t-sm);
}
.stat + .stat { border-top: 1px solid var(--line-soft); }
.stat > span:first-child { color: var(--muted); }
.stat > span:last-child { font-weight: var(--w-med); text-align: right; }

/* ------------------------------------------------------- allocation bar - */

.alloc { margin-top: var(--s3); }
.alloc-bar {
  display: flex;
  height: 10px;
  border-radius: var(--r-pill);
  overflow: hidden;
  background: var(--panel-2);
}
.alloc-bar span { display: block; height: 100%; }
.alloc-bar .invested { background: var(--accent); }
.alloc-bar .reserved { background: var(--warn); }
.alloc-bar .free { background: var(--faint); }
.alloc-legend {
  display: flex;
  gap: var(--s4);
  flex-wrap: wrap;
  margin-top: var(--s3);
  font-size: var(--t-sm);
}
.alloc-legend .item { display: flex; align-items: center; gap: var(--s2); }
.alloc-legend .swatch { width: 8px; height: 8px; border-radius: 2px; flex: none; }
.alloc-legend .invested { background: var(--accent); }
.alloc-legend .reserved { background: var(--warn); }
.alloc-legend .free { background: var(--faint); }
.alloc-legend .k { color: var(--muted); }
.alloc-legend .v { font-weight: var(--w-med); }

/* rank bar on standings */
.rankbar { height: 4px; border-radius: var(--r-pill); background: var(--panel-2); margin-top: var(--s2); overflow: hidden; }
.rankbar span { display: block; height: 100%; background: var(--accent); border-radius: var(--r-pill); }
.row.you { background: var(--panel-2); border-left: 2px solid var(--accent); padding-left: calc(var(--s2) - 2px); }

/* ---------------------------------------------------------------- charts - */

.chart { position: relative; --gutter: 56px; }
/* The gutter is a margin, not an inset, so the absolutely positioned layers
   below can all use inset:0 and stay in lockstep. An inset SVG would size to
   its intrinsic viewBox instead of the box, and the line would drift off the
   dots. */
.chart-plot {
  position: relative;
  height: 220px;
  margin-left: var(--gutter);
}
@media (min-width: 720px) { .chart-plot { height: 280px; } }

/* preserveAspectRatio="none" + vector-effect on the paths lets one
   server-rendered viewBox stretch to any box without distorting the stroke.
   Nothing inside is <text>, which is why the labels are HTML.

   Everything that maps to chart coordinates is inset by the same gutter, so
   the axis labels sit beside the plot rather than on top of it. They used to
   carry an opaque background and punch visible holes through the area fill. */
.chart-plot svg,
.chart-grid,
.chart-dots { position: absolute; inset: 0; }
.chart-plot svg { width: 100%; height: 100%; display: block; }

.chart-grid { pointer-events: none; }
.chart-grid .line {
  position: absolute;
  left: 0; right: 0;
  border-top: 1px dashed var(--line);
}
.chart-grid .label {
  position: absolute;
  left: calc(var(--gutter) * -1);
  width: calc(var(--gutter) - var(--s2));
  text-align: right;
  transform: translateY(-50%);
  font-size: var(--t-xs);
  color: var(--faint);
}
/* One dot per batch. The single clearest signal that this market clears
   nightly rather than continuously — so they are drawn, not smoothed over.
   HTML, not SVG: a stretched viewBox turns a <circle> into an ellipse. */
.chart-dots { pointer-events: none; }
.chart-dots .dot {
  position: absolute;
  width: 5px; height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: var(--r-pill);
  background: var(--bg);
  border: 1.5px solid currentColor;
  opacity: 0.55;
}
.chart-dots .dot.hover {
  width: 9px; height: 9px;
  margin: -4.5px 0 0 -4.5px;
  opacity: 1;
  background: currentColor;
  box-shadow: 0 0 0 4px color-mix(in srgb, currentColor 22%, transparent);
}
.chart-dots .dot.last {
  width: 9px; height: 9px;
  margin: -4.5px 0 0 -4.5px;
  opacity: 1;
  background: currentColor;
  box-shadow: 0 0 0 4px color-mix(in srgb, currentColor 22%, transparent);
}
.chart.up .chart-dots { color: var(--up); }
.chart.down .chart-dots { color: var(--down); }
.chart.flat .chart-dots { color: var(--flat); }

.chart-xlabels {
  position: relative;
  height: 1.2em;
  margin: var(--s2) 0 0 var(--gutter);
  font-size: var(--t-xs);
  color: var(--faint);
}
.chart-xlabels .x { position: absolute; transform: translateX(-50%); white-space: nowrap; }
.chart-xlabels .x:first-child { transform: none; }
.chart-xlabels .x:last-child { transform: translateX(-100%); }

.chart-legend {
  display: flex;
  gap: var(--s4);
  flex-wrap: wrap;
  font-size: var(--t-xs);
  color: var(--muted);
  margin-top: var(--s3);
}
.chart-legend .item { display: flex; align-items: center; gap: var(--s2); }
.chart-legend .key { width: 14px; height: 0; border-top: 2px solid currentColor; flex: none; }
.chart-legend .key.dash { border-top-style: dashed; }
.chart-legend .price { color: var(--up); }
.chart-legend .price.down { color: var(--down); }
.chart-legend .fair { color: var(--muted); }

.chart-readout {
  font-size: var(--t-sm);
  color: var(--muted);
  margin-top: var(--s3);
  min-height: 1.5em;
}
.chart-readout strong { color: var(--text); font-weight: var(--w-semi); }

.spark { display: block; width: 100%; height: 100%; overflow: visible; }

/* ----------------------------------------------------------------- forms - */

label { display: block; margin: 0 0 var(--s1); color: var(--muted); font-size: var(--t-sm); }
.field + .field { margin-top: var(--s4); }

input[type=text], input[type=email], input[type=number], input[type=password], input[type=search], select, textarea {
  width: 100%;
  padding: var(--s3);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-variant-numeric: tabular-nums;
}
input:focus-visible, select:focus-visible, textarea:focus-visible { border-color: var(--accent); }
input::placeholder { color: var(--faint); }
input.big { font-size: var(--t-lg); font-weight: var(--w-semi); padding: var(--s3) var(--s3); }

.helptext { color: var(--faint); font-size: var(--t-xs); margin-top: var(--s1); }
.errorlist { color: var(--down); list-style: none; padding: 0; margin: var(--s1) 0 0; font-size: var(--t-xs); }

/* segmented buy/sell control. Django renders RadioSelect as nested divs, so
   this styles the label and hides the input rather than relying on markup. */
.seg { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s1); background: var(--panel-2); border-radius: var(--r-md); padding: var(--s1); }
.seg div { display: block; }
.seg label {
  display: block;
  margin: 0;
  text-align: center;
  padding: var(--s2) var(--s3);
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  font-weight: var(--w-semi);
  color: var(--muted);
  cursor: pointer;
  text-transform: capitalize;
  transition: background var(--dur), color var(--dur);
}
.seg input { position: absolute; opacity: 0; pointer-events: none; }
.seg label:has(input:checked) { background: var(--panel); color: var(--text); box-shadow: var(--e1); }
.seg label:has(input[value="buy"]:checked) { color: var(--up); }
.seg label:has(input[value="sell"]:checked) { color: var(--down); }
.seg label:has(input:focus-visible) { box-shadow: var(--ring); }

/* --------------------------------------------------------------- buttons - */

button, .btn {
  display: inline-block;
  padding: var(--s3) var(--s5);
  border-radius: var(--r-md);
  border: 0;
  background: var(--accent);
  color: var(--accent-ink);
  font: inherit;
  font-weight: var(--w-semi);
  cursor: pointer;
  text-align: center;
}
button:hover, .btn:hover { filter: brightness(1.08); text-decoration: none; }
button:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-block, button.block { display: block; width: 100%; }

/* The submit follows the side, with no JavaScript at all. */
form:has(input[value="sell"]:checked) button.side-aware { background: var(--down); color: #fff; }

button.link, .btn-link {
  background: none;
  color: var(--muted);
  padding: 0;
  font-weight: 400;
  text-decoration: underline;
}
button.link:hover { color: var(--text); filter: none; }

button.ghost {
  background: none;
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: var(--t-xs);
  font-weight: var(--w-med);
  padding: var(--s1) var(--s3);
  border-radius: var(--r-pill);
}
button.ghost:hover { color: var(--text); border-color: var(--muted); filter: none; }

/* quick-set cluster under the limit input; hidden until app.js wires it.
   One joined pair per side, swapped whole by app.js: current·max buying,
   current·clear selling. */
.limit-tools { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s2); }
.limit-tools button { font-variant-numeric: tabular-nums; }
.limit-tools[hidden] { display: none; }
.limit-tools .pair { display: inline-flex; }
.limit-tools .pair[hidden] { display: none; }
.limit-tools .available { align-self: center; font-size: var(--t-xs); color: var(--muted); font-variant-numeric: tabular-nums; }
.limit-tools .pair button { border-radius: 0; }
.limit-tools .pair button:first-child { border-radius: var(--r-pill) 0 0 var(--r-pill); }
.limit-tools .pair button:last-child { border-radius: 0 var(--r-pill) var(--r-pill) 0; border-left: 0; }

/* ---------------------------------------------------------------- notices - */

.messages { list-style: none; padding: 0; margin: 0 0 var(--s4); }
.messages li {
  display: flex;
  align-items: flex-start;
  gap: var(--s2);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--panel);
  margin-bottom: var(--s2);
  font-size: var(--t-sm);
}
.messages li.error { border-color: color-mix(in srgb, var(--down) 45%, transparent); background: var(--down-bg); color: var(--down); }
.messages li.success { border-color: color-mix(in srgb, var(--up) 45%, transparent); background: var(--up-bg); color: var(--up); }

/* the expiry rule deserves to be read, not skimmed past in grey 12px prose */
.callout {
  display: flex;
  gap: var(--s3);
  align-items: flex-start;
  padding: var(--s3);
  border-radius: var(--r-md);
  background: var(--warn-bg);
  border: 1px solid color-mix(in srgb, var(--warn) 30%, transparent);
  font-size: var(--t-xs);
  color: var(--text);
  line-height: 1.45;
}
.callout svg { flex: none; color: var(--warn); margin-top: 1px; }

/* ----------------------------------------------------------------- table - */

/* Only the batch history stays a real table. It is reference material and
   genuinely tabular; everything else is the row primitive. */
.tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; font-size: var(--t-sm); }
th, td { padding: var(--s2) var(--s3); text-align: right; border-bottom: 1px solid var(--line-soft); white-space: nowrap; }
th:first-child, td:first-child { text-align: left; padding-left: 0; }
th:last-child, td:last-child { padding-right: 0; }
th {
  color: var(--faint);
  font-weight: var(--w-med);
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
tbody tr:last-child td { border-bottom: 0; }

details.disclose > summary {
  cursor: pointer;
  font-size: var(--t-sm);
  color: var(--muted);
  font-weight: var(--w-med);
  padding: var(--s2) 0;
  list-style: none;
}
details.disclose > summary::-webkit-details-marker { display: none; }
details.disclose > summary::before { content: "▸ "; color: var(--faint); }
details.disclose[open] > summary::before { content: "▾ "; }
details.disclose > summary:hover { color: var(--text); }

pre.code {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s3) var(--s4);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  font-family: var(--ff-mono);
  font-size: var(--t-xs);
  line-height: 1.7;
  color: var(--text);
}
code { font-family: var(--ff-mono); font-size: 0.92em; background: var(--panel-2); padding: 1px 5px; border-radius: var(--r-sm); }

/* ------------------------------------------------------------- auth pages - */

.auth {
  max-width: 440px;
  margin: 0 auto;
  padding: var(--s7) var(--s4) var(--s8);
}
.auth .mark { text-align: center; margin-bottom: var(--s5); }
.auth .mark .name {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-xl);
  font-weight: var(--w-bold);
  letter-spacing: -0.035em;
}
.auth .mark .name svg { color: var(--accent); }
.auth .mark .tagline { margin: var(--s2) 0 0; font-size: var(--t-sm); color: var(--muted); }
.auth .panel { padding: var(--s5); }
.auth-foot { text-align: center; margin-top: var(--s4); font-size: var(--t-xs); color: var(--faint); }

/* --------------------------------------------------------------- utility - */

.divider { height: 1px; background: var(--line); border: 0; margin: var(--s5) 0; }
.hide { display: none !important; }
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.searchbar { display: flex; gap: var(--s2); margin-bottom: var(--s4); }
.searchbar input { flex: 1; }
