/* =========================================================================================
   WhaleRestocks Web Console — "harbor ledger"
   A light, professional operations console. Neutral paper surfaces, one deep marine-blue
   accent for everything interactive, green strictly for success/profit, quiet hairlines.
   ========================================================================================= */

:root {
  /* --- paper surfaces --- */
  --abyss:      #f7f8fa;   /* page floor (clean neutral) */
  --deep:       #fbfcfd;   /* app shell / rail */
  --surface:    #ffffff;   /* panels */
  --surface-2:  #f4f6f9;   /* raised / hover */
  --surface-3:  #eef1f5;   /* inputs / active */
  --line:       rgba(17, 27, 45, .10);
  --line-soft:  rgba(17, 27, 45, .06);
  --line-strong:rgba(17, 27, 45, .16);

  /* --- ink --- */
  --ink:        #17202e;
  --ink-dim:    #4e5b70;
  --ink-faint:  #8791a3;
  --ink-ghost:  #b4bdca;

  /* --- accent: deep marine blue — the ONE interactive color --- */
  --accent:      #2e5fd7;
  --accent-deep: #2349a8;
  --accent-glow: rgba(46, 95, 215, .20);
  --accent-dim:  rgba(46, 95, 215, .09);

  /* --- semantics (status only, never decoration) --- */
  --sonar:      #16935a;   /* success / live / cartable / profit */
  --sonar-deep: #0f7247;
  --sonar-glow: rgba(22, 147, 90, .20);
  --sonar-dim:  rgba(22, 147, 90, .10);

  --amber:      #b07a10;   /* warn / benched / checking / queued */
  --amber-glow: rgba(176, 122, 16, .18);
  --coral:      #d23b4c;   /* danger / failed / banned / fraud */
  --coral-glow: rgba(210, 59, 76, .16);
  --tide:       var(--accent);   /* info / links fold into the accent */
  --tide-glow:  var(--accent-glow);

  /* --- type --- */
  --f-display: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --f-body:    "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --f-mono:    "IBM Plex Mono", ui-monospace, "JetBrains Mono", monospace;

  /* --- geometry --- */
  --rail-w: 232px;
  --radius: 10px;
  --radius-sm: 6px;
  --gap: 18px;
  --shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 6px 20px -10px rgba(16, 24, 40, .10);
  --shadow-glow: 0 0 0 1px var(--accent-dim), 0 6px 20px -10px rgba(16, 24, 40, .10);
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--f-body);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--abyss);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-deep); }

svg.ico { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; flex: none; }

::selection { background: var(--accent-dim); color: var(--ink); }

/* scrollbars */
*::-webkit-scrollbar { width: 11px; height: 11px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: #d7dbe2; border-radius: 99px; border: 3px solid transparent; background-clip: padding-box; }
*::-webkit-scrollbar-thumb:hover { background: #bdc4cf; background-clip: padding-box; }

/* =========================================================================================
   APP SHELL — fixed command rail + top fleet strip + content
   ========================================================================================= */
.shell { display: grid; grid-template-columns: var(--rail-w) 1fr; min-height: 100vh; }

/* ---- command rail (sidebar) ----
   Four fixed bands: brand, instance scope, scrolling grouped nav, foot. Only the nav scrolls,
   so the brand and the sign-out are always reachable no matter how many tabs exist. */
.rail {
  position: sticky; top: 0; align-self: start;
  height: 100vh; display: flex; flex-direction: column;
  background: var(--deep);
  border-right: 1px solid var(--line);
  padding: 0;
}

/* brand — mark sits in a tinted tile so it reads as a logo, not a stray glyph */
.rail__brand {
  display: flex; align-items: center; gap: 11px;
  padding: 16px 16px 15px;
  border-bottom: 1px solid var(--line-soft);
}
.rail__mark {
  width: 34px; height: 34px; flex: none; color: var(--accent);
  background: var(--accent-dim); border-radius: 9px; padding: 5px;
  stroke-width: 1.7;
}
.rail__title { font-family: var(--f-display); font-weight: 650; letter-spacing: -.1px; font-size: 14.5px; line-height: 1.1; min-width: 0; }
.rail__title small { display: block; font-family: var(--f-mono); font-weight: 400; font-size: 9px; letter-spacing: 1.6px; text-transform: uppercase; color: var(--ink-faint); margin-top: 3px; }
.rail__close { display: none; }   /* phone-only dismiss; see the drawer block below */

/* instance switcher — a single control with a live status dot baked in */
.rail__instance { padding: 12px 14px; border-bottom: 1px solid var(--line-soft); }
.rail__instance label { display: block; font-family: var(--f-mono); font-size: 9px; letter-spacing: 1.6px; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 6px; }
.rail__pick {
  position: relative; display: flex; align-items: center;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
  transition: border-color .14s, box-shadow .14s;
}
.rail__pick:hover { border-color: var(--line-strong); }
.rail__pick:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }
.rail__pick.is-scoped { border-color: var(--accent-glow); background: var(--accent-dim); }
.rail__pickdot { width: 6px; height: 6px; border-radius: 99px; background: var(--ink-ghost); flex: none; margin-left: 10px; }
.rail__pickdot.on  { background: var(--sonar); box-shadow: 0 0 0 3px var(--sonar-dim); }
.rail__pickdot.off { background: var(--ink-ghost); }
.rail__pick select {
  flex: 1; min-width: 0; border: 0; background: none; box-shadow: none;
  padding: 7px 26px 7px 8px; font-size: 12px; color: var(--ink);
}
.rail__pick select:focus { outline: none; box-shadow: none; }

/* nav — the only scrolling band */
.rail__nav {
  flex: 1; overflow-y: auto; overscroll-behavior: contain;
  padding: 8px 9px 14px; display: flex; flex-direction: column; gap: 1px;
}
.rail__group {
  font-family: var(--f-mono); font-size: 8.5px; letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--ink-ghost); padding: 0 11px; margin: 13px 0 5px;
}
.rail__nav > .rail__group:first-child { margin-top: 2px; }
.navlink {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 11px; border-radius: 7px;
  color: var(--ink-dim); font-weight: 500; font-size: 13px;
  position: relative; transition: background .14s, color .14s;
}
.navlink svg { width: 16px; height: 16px; flex: none; opacity: .7; transition: opacity .14s, color .14s; }
.navlink__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.navlink:hover { background: var(--surface-2); color: var(--ink); }
.navlink:hover svg { opacity: 1; }
.navlink.is-active {
  background: var(--accent-dim); color: var(--accent-deep); font-weight: 600;
}
.navlink.is-active svg { opacity: 1; color: var(--accent); }
.navlink.is-active::before {
  content: ""; position: absolute; left: -9px; top: 50%; transform: translateY(-50%);
  width: 3px; height: 18px; border-radius: 0 99px 99px 0;
  background: var(--accent);
}
.navlink:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.navlink__badge { margin-left: auto; font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-faint); flex: none; }
.navlink__badge.live { color: var(--ink); }
.navlink__badge.live::before {
  content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: #34c98e; margin-right: 5px; vertical-align: 1px;
  animation: wr-badge-pulse 1.6s ease-in-out infinite;
}
@keyframes wr-badge-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

.rail__foot { padding: 10px 14px; border-top: 1px solid var(--line-soft); display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.rail__foot .ver { font-family: var(--f-mono); font-size: 10px; color: var(--ink-ghost); }
.rail__out {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12px; color: var(--ink-faint);
  padding: 5px 9px; border-radius: var(--radius-sm); transition: background .14s, color .14s;
}
.rail__out .ico { width: 14px; height: 14px; }
.rail__out:hover { color: var(--coral); background: var(--coral-glow); }

/* ---- main column ---- */
.main { min-width: 0; display: flex; flex-direction: column; }

/* top fleet-health strip — the old console title, now a HUD bar */
.fleet {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  padding: 9px 22px;
  background: rgba(255, 255, 255, .82); backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.fleet__title { font-family: var(--f-display); font-weight: 600; font-size: 13px; letter-spacing: .4px; margin-right: 8px; color: var(--ink); }
.chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 4px 10px; border-radius: 99px;
  background: var(--surface); border: 1px solid var(--line);
  font-family: var(--f-mono); font-size: 11.5px; color: var(--ink-dim);
  white-space: nowrap;
}
.chip b { color: var(--ink); font-weight: 600; }
.chip .dot { width: 7px; height: 7px; border-radius: 99px; background: var(--ink-faint); flex: none; }
.chip.good .dot { background: var(--sonar); }
.chip.warn .dot { background: var(--amber); }
.chip.bad  .dot { background: var(--coral); }
.chip.good b { color: var(--sonar); }
.chip.warn b { color: var(--amber); }
.chip.bad  b { color: var(--coral); }
.fleet__spacer { flex: 1; }
.fleet__clock { font-family: var(--f-mono); font-size: 11.5px; color: var(--ink-faint); }

.content { padding: 26px 22px 60px; max-width: 1480px; width: 100%; }

/* page header */
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; margin-bottom: 22px; }
.page-head__l { min-width: 0; }
.eyebrow { font-family: var(--f-mono); font-size: 10.5px; letter-spacing: 2.4px; text-transform: uppercase; color: var(--accent-deep); margin-bottom: 7px; }
h1 { font-family: var(--f-display); font-weight: 700; font-size: 27px; letter-spacing: -.2px; margin: 0; line-height: 1.1; }
.page-head p { color: var(--ink-dim); margin: 7px 0 0; font-size: 13.5px; max-width: 70ch; }
/* `flex: 0 1 auto` + wrap, not `flex: none`: a header with four actions (Sales) otherwise refuses
   to shrink and pushes the whole document sideways in the band above the 880px stacking rule. */
.page-head__r { display: flex; gap: 10px; align-items: center; flex: 0 1 auto;
  flex-wrap: wrap; justify-content: flex-end; }

h2 { font-family: var(--f-display); font-weight: 700; font-size: 16px; letter-spacing: -.1px; margin: 0; }
h3 { font-family: var(--f-display); font-weight: 700; font-size: 13.5px; letter-spacing: 0; margin: 0; color: var(--ink); }

/* =========================================================================================
   PANELS / CARDS / STATS
   ========================================================================================= */
.panel {
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.panel__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 15px 18px; border-bottom: 1px solid var(--line-soft); }
.panel__head .sub { font-family: var(--f-mono); font-size: 11px; color: var(--ink-faint); }
.panel__body { padding: 18px; }
.panel__body.flush { padding: 0; }

.grid { display: grid; gap: var(--gap); }
/* grid children default to min-width:auto, so unbreakable content (long paths, proxy
   strings) blows out the track and overflows the row — let every grid item shrink. */
.grid > * { min-width: 0; }
.grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
.grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
.grid.cols-5 { grid-template-columns: repeat(5, 1fr); }
@media (max-width: 1100px) { .grid.cols-4 { grid-template-columns: repeat(2, 1fr); } .grid.cols-3 { grid-template-columns: repeat(2,1fr);} .grid.cols-5 { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px) { .grid.cols-2, .grid.cols-3, .grid.cols-4, .grid.cols-5 { grid-template-columns: 1fr; } }

/* stat card — big mono number, thin accent top rule */
.stat {
  position: relative; overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px 17px 15px;
  box-shadow: var(--shadow);
}
.stat::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px; background: linear-gradient(90deg, var(--accent), transparent 70%); opacity: .45; }
.stat.is-warn::before { background: linear-gradient(90deg, var(--amber), transparent 70%); }
.stat.is-bad::before  { background: linear-gradient(90deg, var(--coral), transparent 70%); }
.stat__label { font-family: var(--f-mono); font-size: 10px; letter-spacing: 1.6px; text-transform: uppercase; color: var(--ink-faint); display: flex; align-items: center; gap: 7px; }
.stat__value { font-family: var(--f-mono); font-weight: 600; font-size: 30px; letter-spacing: -.5px; margin-top: 8px; line-height: 1; color: var(--ink); }
.stat__value .unit { font-size: 14px; color: var(--ink-faint); font-weight: 400; margin-left: 3px; }
.stat__sub { margin-top: 7px; font-size: 11.5px; color: var(--ink-dim); }
.stat.is-good .stat__value { color: var(--sonar); }
.stat.is-warn .stat__value { color: var(--amber); }
.stat.is-bad  .stat__value { color: var(--coral); }

/* =========================================================================================
   PILLS / BADGES / DOTS
   ========================================================================================= */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 2.5px 9px; border-radius: 99px;
  font-family: var(--f-mono); font-size: 11px; font-weight: 500; letter-spacing: .2px;
  border: 1px solid var(--line-strong); color: var(--ink-dim); background: var(--surface);
}
.pill .dot { width: 6px; height: 6px; border-radius: 99px; background: currentColor; }
.pill.good { color: var(--sonar-deep); border-color: var(--sonar-dim); background: var(--sonar-dim); }
.pill.warn { color: var(--amber); border-color: var(--amber-glow); background: rgba(176, 122, 16, .07); }
.pill.bad  { color: var(--coral); border-color: var(--coral-glow); background: rgba(210, 59, 76, .06); }
.pill.info { color: var(--accent-deep); border-color: var(--accent-dim); background: var(--accent-dim); }
.pill.idle { color: var(--ink-faint); }

/* dashboard per-engine pool gauges (tmpt + anon-jar buffers), live-updated */
.pool-cell { display: inline-flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.pill.pool { padding: 2.5px 8px; gap: 5px; }
.pill.pool .ico { width: 13px; height: 13px; opacity: .85; }
.pill.pool b { color: inherit; font-weight: 600; font-variant-numeric: tabular-nums; }
.pill.pool .u { color: var(--ink-faint); font-weight: 400; letter-spacing: .3px; }

.pulse { position: relative; }
.pulse::after {
  content: ""; position: absolute; left: -3px; top: 50%; width: 6px; height: 6px;
  transform: translateY(-50%); border-radius: 99px; background: currentColor;
  animation: sonar-ping 1.8s ease-out infinite;
}
@keyframes sonar-ping {
  0%   { box-shadow: 0 0 0 0 currentColor; opacity: .7; }
  70%  { box-shadow: 0 0 0 9px transparent; opacity: 0; }
  100% { box-shadow: 0 0 0 0 transparent; opacity: 0; }
}

/* =========================================================================================
   BUTTONS
   ========================================================================================= */
.btn {
  display: inline-flex; align-items: center; gap: 8px; justify-content: center;
  font-family: var(--f-display); font-weight: 600; font-size: 13px; letter-spacing: .3px;
  padding: 8px 15px; border-radius: var(--radius-sm); cursor: pointer;
  background: var(--surface-2); color: var(--ink); border: 1px solid var(--line-strong);
  transition: background .14s, border-color .14s, transform .05s, box-shadow .14s;
  white-space: nowrap; text-decoration: none;
}
.btn:hover { background: var(--surface-3); border-color: var(--line-strong); }
.btn:active { transform: translateY(1px); }
.btn svg { width: 15px; height: 15px; }
.btn.primary {
  background: var(--accent);
  color: #ffffff; border-color: transparent; box-shadow: 0 1px 2px rgba(16, 24, 40, .10);
}
.btn.primary:hover { background: var(--accent-deep); }
.btn.danger { color: var(--coral); border-color: var(--coral-glow); }
.btn.danger:hover { background: rgba(210, 59, 76, .08); border-color: var(--coral); }
.btn.ghost { background: transparent; border-color: var(--line); }
.btn.ghost:hover { background: var(--surface); }
.btn.sm { padding: 5px 10px; font-size: 12px; }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-row { display: flex; gap: 9px; flex-wrap: wrap; }

/* =========================================================================================
   TABLES
   ========================================================================================= */
.table-wrap { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: 13px; }
table.data th {
  text-align: left; font-family: var(--f-mono); font-weight: 500; font-size: 10px;
  letter-spacing: 1.4px; text-transform: uppercase; color: var(--ink-faint);
  padding: 11px 14px; border-bottom: 1px solid var(--line); white-space: nowrap;
}
table.data td { padding: 11px 14px; border-bottom: 1px solid var(--line-soft); color: var(--ink-dim); vertical-align: middle; }
table.data tr:last-child td { border-bottom: none; }
table.data tbody tr { transition: background .12s; }
table.data tbody tr:hover { background: var(--surface); }
table.data td.mono, table.data .mono { font-family: var(--f-mono); color: var(--ink); }
table.data td.num { font-family: var(--f-mono); text-align: right; }
table.data th.num { text-align: right; }
.t-primary { color: var(--ink); font-weight: 500; }

/* =========================================================================================
   FORMS
   ========================================================================================= */
label.field { display: block; margin-bottom: 14px; }
.field > span { display: block; font-family: var(--f-mono); font-size: 10.5px; letter-spacing: 1.2px; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 6px; }
input[type=text], input[type=password], input[type=number], input[type=search], input[type=url], select, textarea {
  width: 100%; font-family: var(--f-body); font-size: 13.5px; color: var(--ink);
  background: var(--surface-3); border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  padding: 9px 12px; transition: border-color .14s, box-shadow .14s; outline: none;
}
input[type=text].mono, input.mono, textarea.mono, select.mono { font-family: var(--f-mono); }
input:focus, select:focus, textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-dim); }
input::placeholder, textarea::placeholder { color: var(--ink-ghost); }
textarea { resize: vertical; min-height: 96px; line-height: 1.55; }
select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%2388a2b0' stroke-width='2'%3E%3Cpath d='M3 5l3 3 3-3'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 11px center; padding-right: 30px; }
/* Fleet table profile-assign dropdown: size to the selected profile name (not the narrow
   column's min-content) so it isn't clipped behind the arrow. Floor keeps short names usable. */
select[data-assign] { width: auto; min-width: 132px; max-width: 240px; }
.checkbox { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; color: var(--ink-dim); }
.checkbox input { width: auto; accent-color: var(--accent); }
.help { font-size: 11.5px; color: var(--ink-faint); margin-top: 5px; }
.inline-form { display: flex; gap: 9px; align-items: flex-end; flex-wrap: wrap; }

/* =========================================================================================
   EMPTY STATE / MISC
   ========================================================================================= */
.empty { text-align: center; padding: 46px 20px; color: var(--ink-faint); }
.empty svg { width: 38px; height: 38px; opacity: .45; margin-bottom: 12px; color: var(--accent); }
.empty h3 { color: var(--ink-dim); margin-bottom: 5px; }
.muted { color: var(--ink-faint); }
.mono { font-family: var(--f-mono); }
.tnum { font-family: var(--f-mono); font-variant-numeric: tabular-nums; }
.right { text-align: right; }
.nowrap { white-space: nowrap; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 1px; }
hr.rule { border: none; border-top: 1px solid var(--line-soft); margin: 18px 0; }
.stack { display: flex; flex-direction: column; gap: var(--gap); }
.row { display: flex; gap: var(--gap); align-items: center; }
.banner { display: flex; align-items: center; gap: 11px; padding: 11px 15px; border-radius: var(--radius-sm); font-size: 13px; border: 1px solid var(--line-strong); background: var(--surface); margin-bottom: 18px; }
.banner.warn { border-color: var(--amber-glow); background: rgba(176, 122, 16, .06); color: var(--amber); }
.banner.bad { border-color: var(--coral-glow); background: rgba(210, 59, 76, .05); color: var(--coral); }
.banner svg { width: 17px; height: 17px; flex: none; }

/* secret mask */
.secret { font-family: var(--f-mono); color: var(--ink-faint); }
.reveal { cursor: pointer; border-bottom: 1px dotted var(--ink-ghost); }

/* =========================================================================================
   MODAL / DRAWER
   ========================================================================================= */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 70; display: none;
  background: rgba(26, 42, 56, .42); backdrop-filter: blur(3px);
  align-items: flex-start; justify-content: center; padding: 7vh 18px 18px;
}
.modal-backdrop.open { display: flex; }
.modal {
  width: 100%; max-width: 720px; max-height: 84vh; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: var(--shadow); animation: rise .22s cubic-bezier(.2,.7,.3,1) both;
}
.modal.wide { max-width: 920px; }
.modal__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--line-soft); }
.modal__head h2 { font-size: 16px; }
.modal__close { cursor: pointer; color: var(--ink-faint); background: none; border: none; padding: 4px; border-radius: 5px; }
.modal__close:hover { color: var(--ink); background: var(--surface-2); }
.modal__body { padding: 20px; overflow-y: auto; }
.modal__foot { display: flex; align-items: center; justify-content: flex-end; gap: 10px; padding: 14px 20px; border-top: 1px solid var(--line-soft); }
.steps { display: flex; gap: 8px; margin-bottom: 18px; }
.step { flex: 1; height: 3px; border-radius: 99px; background: var(--surface-3); }
.step.active { background: var(--accent); }
.step.done { background: var(--accent-deep); }
.pick-list { display: flex; flex-direction: column; gap: 8px; max-height: 46vh; overflow-y: auto; }
.pick {
  display: flex; align-items: center; gap: 12px; padding: 11px 13px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface-2);
  cursor: pointer; transition: border-color .12s, background .12s;
}
.pick:hover { border-color: var(--accent-glow); }
.pick.sel { border-color: var(--accent); background: var(--accent-dim); }
.pick input { accent-color: var(--accent); }
.pick__meta { min-width: 0; flex: 1; }
.pick__t { color: var(--ink); font-weight: 500; }
.pick__s { font-size: 11.5px; color: var(--ink-faint); font-family: var(--f-mono); margin-top: 2px; }
.chips-edit { display: flex; flex-wrap: wrap; gap: 6px; }
.chip-toggle { cursor: pointer; user-select: none; padding: 4px 10px; border-radius: 99px; font-family: var(--f-mono); font-size: 11.5px; border: 1px solid var(--line-strong); color: var(--ink-dim); background: var(--surface-2); }
.chip-toggle.on { color: var(--accent-deep); border-color: var(--accent); background: var(--accent-dim); }
.spinner { width: 16px; height: 16px; border: 2px solid var(--line-strong); border-top-color: var(--accent); border-radius: 50%; animation: spin .7s linear infinite; display: inline-block; }
@keyframes spin { to { transform: rotate(360deg); } }

/* tiny inline controls used in data tables */
.toggle { cursor: pointer; display: inline-flex; align-items: center; gap: 6px; font-family: var(--f-mono); font-size: 11px; padding: 3px 9px; border-radius: 99px; border: 1px solid var(--line-strong); color: var(--ink-faint); background: var(--surface); }
.toggle.on { color: var(--accent-deep); border-color: var(--accent-glow); background: var(--accent-dim); }
.toggle .dot { width: 6px; height: 6px; border-radius: 99px; background: currentColor; }
.inp-mini { width: 64px; padding: 4px 7px; font-size: 12px; }
.sel-mini { padding: 4px 24px 4px 8px; font-size: 12px; }
.icon-btn { cursor: pointer; color: var(--ink-faint); background: none; border: 1px solid var(--line); border-radius: 5px; padding: 4px; display: inline-flex; }
.icon-btn:hover { color: var(--ink); border-color: var(--line-strong); background: var(--surface-2); }
.icon-btn.danger:hover { color: var(--coral); border-color: var(--coral-glow); }
.icon-btn.spin { color: var(--accent); pointer-events: none; }
.icon-btn.spin svg { animation: spin .7s linear infinite; }
.btn.busy { opacity: .7; pointer-events: none; }
.btn.busy svg { animation: spin .7s linear infinite; }

/* =========================================================================================
   TOASTS
   ========================================================================================= */
.toasts { position: fixed; right: 18px; bottom: 18px; z-index: 80; display: flex; flex-direction: column; gap: 10px; max-width: 360px; }
.toast {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 12px 14px; border-radius: var(--radius-sm); font-size: 13px;
  background: var(--surface-2); border: 1px solid var(--line-strong);
  box-shadow: var(--shadow); animation: toast-in .25s ease both;
}
.toast.good { border-left: 3px solid var(--sonar); }
.toast.warn { border-left: 3px solid var(--amber); }
.toast.bad  { border-left: 3px solid var(--coral); }
.toast.info { border-left: 3px solid var(--tide); }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } }

/* =========================================================================================
   LOGIN
   ========================================================================================= */
.gate { min-height: 100vh; display: grid; place-items: center; padding: 24px; }
.gate__card { width: 100%; max-width: 380px; }
.gate__brand { display: flex; flex-direction: column; align-items: center; gap: 14px; margin-bottom: 26px; text-align: center; }
.gate__mark { width: 58px; height: 58px; color: var(--accent); }
.gate__brand h1 { font-size: 22px; }
.gate__brand small { font-family: var(--f-mono); font-size: 10px; letter-spacing: 3px; text-transform: uppercase; color: var(--ink-faint); }
.gate .panel__body { padding: 24px; }
.gate .err { color: var(--coral); font-size: 13px; margin-bottom: 14px; text-align: center; }

/* staggered page-load reveal */
.reveal-in { animation: rise .5s cubic-bezier(.2,.7,.3,1) both; }
.reveal-in:nth-child(1) { animation-delay: .02s; }
.reveal-in:nth-child(2) { animation-delay: .07s; }
.reveal-in:nth-child(3) { animation-delay: .12s; }
.reveal-in:nth-child(4) { animation-delay: .17s; }
.reveal-in:nth-child(5) { animation-delay: .22s; }
@keyframes rise { from { opacity: 0; transform: translateY(12px); } }
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } }

/* responsive rail collapse */
@media (max-width: 880px) {
  .shell { grid-template-columns: 1fr; }
  .rail { position: fixed; left: 0; top: 0; width: var(--rail-w); transform: translateX(-100%); transition: transform .2s; z-index: 60; }
  .rail.open { transform: none; }
  .content { padding: 20px 14px 50px; }
}
.rail-toggle { display: none; }
@media (max-width: 880px) { .rail-toggle { display: inline-flex; } }

/* ---- curate & filter modal: two-column layout + interactive seat map ---- */
.cur-grid { display: grid; grid-template-columns: 300px 1fr; gap: 18px; }
@media (max-width: 760px) { .cur-grid { grid-template-columns: 1fr; } }
.cur-left { display: flex; flex-direction: column; gap: 14px; }
.cur-tabs { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.cur-tab { background: none; border: 1px solid var(--line-soft); color: var(--ink-dim);
           border-radius: 7px; padding: 4px 12px; cursor: pointer; font-size: 12px; }
.cur-tab.active { border-color: var(--accent); color: var(--accent-deep); }

.seatmap-wrap { width: 100%; max-height: 52vh; overflow: auto; position: relative;
                background: var(--surface-2); border: 1px solid var(--line-soft);
                border-radius: 10px; }
.seatmap { width: 100%; height: auto; display: block; }
.seatmap .seg { fill: var(--surface); stroke: var(--line-soft); stroke-width: 6;
                cursor: pointer; transition: fill .08s; }
.seatmap .seg:hover { fill: var(--ink-faint); }
.seatmap .seg.sel { fill: var(--accent); stroke: var(--accent); }
.seatmap .seg.ga { stroke: var(--amber); stroke-dasharray: 18 10; }
.seatmap .seg.ga.sel { fill: var(--amber); }
/* fitted in-section name labels: centered in each shape, size-capped so they never
   overflow it; white over our own selected/pending fill, quiet ink otherwise */
.seatmap .seg-name { fill: var(--ink-dim); text-anchor: middle; dominant-baseline: middle;
                     pointer-events: none; font-family: var(--f-mono); font-weight: 600; }
.seatmap .seg-name.on-fill { fill: #fff; }

.map-legend { margin-top: 8px; font-size: 11px; color: var(--ink-dim);
              display: flex; align-items: center; gap: 6px; }
.map-legend .lg { width: 12px; height: 12px; border-radius: 3px; display: inline-block;
                  background: var(--surface); border: 1px solid var(--line-soft); }
.map-legend .lg.sel { background: var(--accent); border-color: var(--accent); }
.map-legend .lg.ga { border-color: var(--amber); }
.map-status { padding: 24px; text-align: center; font-size: 13px; }

/* exclude-type chips reuse .chip-toggle but turn coral when active (excluded) */
.chip-toggle.danger.on { background: var(--coral); border-color: var(--coral); color: #fff; }

/* background venue art (the STAGE layer) composited under the interactive paths.
   When present, section polygons become a translucent highlight overlay so the art
   shows through; the art carries its own labels, so ours are hidden. */
.seatmap .seatmap-bg { pointer-events: none; }
.seatmap.has-bg .seg { fill: transparent; stroke: rgba(120,150,170,.35); stroke-width: 4; }
.seatmap.has-bg .seg:hover { fill: var(--accent); fill-opacity: .18; }
.seatmap.has-bg .seg.sel { fill: var(--accent); fill-opacity: .45; stroke: var(--accent); stroke-width: 8; }
.seatmap.has-bg .seg.ga { stroke: var(--amber); }
.seatmap.has-bg .seg.ga.sel { fill: var(--amber); fill-opacity: .45; stroke: var(--amber); }
/* over art, only label sections whose fill covers the art's own baked label */
.seatmap.has-bg .seg-name { display: none; }
.seatmap.has-bg .seg-name.show { display: block; }

/* quick section-group chips (Floor / 100s / 200s / TERRACE LEVEL / ...) */
.cur-groups { margin-bottom: 10px; }
.cur-groups__head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.cur-groups__lbl { font-size: 11px; color: var(--ink-dim); text-transform: uppercase; letter-spacing: .04em; margin-right: auto; }
/* cap the groups strip so a venue with many groups never shoves the map off-screen */
#secGroups { max-height: 92px; overflow-y: auto; padding-right: 2px; }
.chip-toggle.group { border-color: var(--accent); color: var(--ink-dim); }
.chip-toggle.group.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.chip-toggle.group.part { border-style: dashed; color: var(--ink); }
.chip-toggle.group .grp-n { opacity: .6; font-size: 10px; }

/* excluded-type chip showing the code + its human description (e.g. "PLAT1 Official Platinum") */
.chip-toggle .chip-sub { opacity: .7; font-size: 11px; font-weight: 400; }
.chip-toggle.danger.on .chip-sub { opacity: .9; }

/* section price tiers (curate modal): tier rows, the amber pending-tier build state, and
   the per-section price tag on chips / outline on the map */
.tier-list { display: flex; flex-direction: column; gap: 6px; margin: 2px 0 8px; }
.tier-row { display: flex; align-items: center; gap: 8px; padding: 6px 8px 6px 10px;
  border: 1px solid var(--line-soft); border-radius: 9px; background: var(--surface-2); font-size: 12px; }
.tier-row .tier-price { font-family: var(--f-mono); font-weight: 600; color: var(--accent-deep); white-space: nowrap; }
.tier-row .tier-secs { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; color: var(--ink-dim); }
.tier-row .icon-btn { flex: none; font-size: 13px; line-height: 1; }
.tier-editor { border: 1px dashed var(--amber); border-radius: 9px; padding: 10px;
  margin: 2px 0 8px; background: rgba(176,122,16,.06); }
.tier-editor__hint { font-size: 11px; color: var(--ink-dim); margin-bottom: 8px; }
.chip-toggle.pend { border-color: var(--amber); color: var(--amber); background: rgba(176,122,16,.10); box-shadow: inset 0 0 0 1px var(--amber); }
.chip-toggle .tier-tag { font-family: var(--f-mono); font-size: 10px; font-weight: 600; color: var(--accent-deep); margin-left: 5px; }
.chip-toggle.pend .tier-tag { color: var(--amber); }
.seatmap .seg.tiered { stroke: var(--accent-deep); stroke-width: 12; }
.seatmap .seg.pend { fill: var(--amber); fill-opacity: .6; stroke: var(--amber); }
.seatmap.has-bg .seg.tiered { stroke: var(--accent-deep); stroke-width: 8; }
.seatmap.has-bg .seg.pend { fill: var(--amber); fill-opacity: .5; stroke: var(--amber); stroke-width: 8; }
/* a map area that couldn't be reconciled to a manifest section — shown for context but
   not a clickable carting target */
.seatmap .seg.unmatched { opacity: .28; pointer-events: none; }

/* AutoPrice aggressiveness dial: one slider, live % readout, banded hint */
.ap-aggro { display: flex; align-items: center; gap: 10px; margin: 4px 0 10px; }
.ap-aggro input[type="range"] { flex: 1; accent-color: var(--accent); cursor: pointer; min-width: 0; }
.ap-aggro__end { font-size: 10px; color: var(--ink-faint); text-transform: uppercase;
  letter-spacing: .05em; white-space: nowrap; flex: none; }
.ap-aggro__val { font-weight: 700; font-size: 14px; color: var(--accent-deep);
  min-width: 46px; text-align: right; flex: none; }

/* hover price tooltip on the curate map: the hovered section's name + the price cap
   that applies to it (tier > event max), floating just above the cursor */
.map-tip { position: absolute; z-index: 6; pointer-events: none; background: var(--ink);
  color: #fff; border-radius: 7px; padding: 6px 10px; line-height: 1.4;
  box-shadow: var(--shadow); white-space: nowrap; max-width: 240px; overflow: hidden; }
.map-tip[hidden] { display: none; }
.map-tip b { display: block; font-family: var(--f-mono); font-size: 11px; font-weight: 600;
  letter-spacing: .04em; opacity: .85; overflow: hidden; text-overflow: ellipsis; }
.map-tip__price { display: block; font-family: var(--f-mono); font-size: 12.5px; font-weight: 700; }
.map-tip__price.pend { color: #ffca6b; }
.map-tip__src { font-size: 9.5px; font-weight: 400; opacity: .6; letter-spacing: .06em;
  text-transform: uppercase; }

/* AutoPrice (events page): VS-link tag on rows, the review banner + flag pill, and the
   live status strip that narrates each TM/VividSeats fetch during a run */
.vs-tag { display: inline-flex; align-items: center; font-family: var(--f-mono); font-size: 9.5px;
  font-weight: 700; letter-spacing: .06em; padding: 2px 6px; border-radius: 5px;
  border: 1px solid var(--line-strong); color: var(--ink-faint); background: var(--surface);
  vertical-align: middle; cursor: default; }
.vs-tag.on { color: var(--sonar-deep); border-color: var(--sonar-dim); background: var(--sonar-dim);
             cursor: pointer; }
.vs-tag.on:hover { filter: brightness(.93); }
/* Login glyph: reuses .vs-tag / .vs-tag.on colours (green when ON), but is always clickable
   and holds a 12px line-icon instead of the 2-char VS text (svg.ico defaults to 18px). */
.vs-tag.login-tag { cursor: pointer; padding: 2px 5px; }
.vs-tag.login-tag .ico { width: 12px; height: 12px; }
/* Monitor-Mode glyph: the literal "M", same green-when-ON / white-when-OFF treatment as the
   login + queue tags. Fixed min-width so a one-character label still reads as a button. */
.vs-tag.monitor-tag { cursor: pointer; padding: 2px 5px; min-width: 18px; justify-content: center; }
.pill.ap-flag { cursor: pointer; }
.pill.ap-flag:hover { filter: brightness(.94); }

/* =========================================================================================
   EVENTS TABLE — fixed geometry
   The complaint this solves: a long event title used to widen the Event column, which shoved
   every other cell sideways, and the Filters cell wrapped onto a second line whenever a row had
   a few extra pills — so two adjacent rows never lined up.

   The fix is structural, not cosmetic:
     · table-layout: fixed + <colgroup> widths  -> column x-positions are decided by the CSS,
       never by the content, so no row can move another row's controls.
     · both title lines clamp to ONE line with an ellipsis -> every name block is exactly 2 lines.
     · the pill strip is nowrap and scrolls inside its own column instead of wrapping.
   Result: identical row height and identical control positions for every event.
   ========================================================================================= */
.ev-table { table-layout: fixed; width: 100%; }
.ev-c-sel   { width: 38px; }
.ev-c-main  { width: auto; }        /* the only elastic column */
.ev-c-aco   { width: 78px; }
.ev-c-qty   { width: 86px; }
.ev-c-offer { width: 118px; }
.ev-c-flt   { width: 210px; }
.ev-c-gates { width: 96px; }
.ev-c-act   { width: 150px; }   /* 4 buttons: explore, refetch, curate, archive (28px + 5px gap each) */

.ev-table td { vertical-align: middle; }
.ev-table th.ev-sel, .ev-table td.ev-sel { text-align: center; padding-left: 8px; padding-right: 8px; }

/* name block — two clamped lines, so row height never depends on the title */
.ev-main { min-width: 0; }
.ev-main .t-primary {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-weight: 550; line-height: 1.35;
}
.ev-meta {
  font-size: 11px; line-height: 1.45;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ev-meta__hi { color: var(--ink-dim); }
.ev-meta__link { color: var(--ink-faint); }
.ev-meta__link:hover { color: var(--accent); }

/* controls sized to their columns so they can't spill */
.ev-aco .toggle { width: 100%; justify-content: center; }
.ev-qty .inp-mini { width: 100%; }
.ev-offer .inp-mini { width: 100%; }

/* pill strip — one line, scrolls in place, never wraps the row taller */
.ev-flt { min-width: 0; }
.filt-cell {
  display: flex; align-items: center; gap: 5px;
  flex-wrap: nowrap; overflow-x: auto; min-width: 0;
  scrollbar-width: none; -ms-overflow-style: none;
}
.filt-cell::-webkit-scrollbar { display: none; }
.filt-cell > * { flex: none; }
.ev-allsec { font-size: 11px; }

/* gates + actions — fixed lanes, so the glyphs are at the same x on every single row */
.ev-gates { white-space: nowrap; }
.ev-gates > * { margin-right: 4px; }
.ev-gates > *:last-child { margin-right: 0; }
.ev-act { white-space: nowrap; text-align: right; }
.ev-act > .icon-btn { margin-left: 5px; }
.ev-act > .icon-btn:first-child { margin-left: 0; }
.ap-review { display: flex; align-items: center; gap: 9px; margin: 0 0 14px; padding: 9px 14px;
  border: 1px solid var(--amber-glow); border-left: 3px solid var(--amber); border-radius: var(--radius-sm);
  background: rgba(176, 122, 16, .07); color: var(--ink-dim); font-size: 12.5px; }
.ap-review .ico { color: var(--amber); flex: none; }
.ap-review b { color: var(--amber); }
.ap-status { display: flex; align-items: center; gap: 10px; margin: 0 0 14px; padding: 9px 14px;
  border: 1px solid var(--line-soft); border-left: 3px solid var(--accent); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink-dim); font-size: 12.5px; }
.ap-status #apStatusStep { margin-left: auto; font-size: 11px; color: var(--ink-faint); }

/* events attention filters (chips beside the search box) */
.flt-chips { display: inline-flex; gap: 6px; align-items: center; }
.flt-chip { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px;
  padding: 4px 10px; border-radius: 999px; border: 1px solid var(--line-strong);
  background: var(--surface); color: var(--ink-dim); cursor: pointer; white-space: nowrap;
  transition: background .12s, color .12s, border-color .12s; }
.flt-chip .ico { width: 13px; height: 13px; }
.flt-chip:hover { background: var(--surface-2); color: var(--ink); }
.flt-chip.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.flt-chip.on .ico { color: #fff; }

/* Cards page filter bar — labelled rows of .flt-chip groups plus the narrowing dropdowns. Sits at
   the top of the Stored-cards panel body (not the summary), so clicking it never toggles the
   <details>. The chips reuse the Events page's .flt-chip so "ticked" looks identical on both. */
.cards-flt { display: flex; flex-direction: column; gap: 7px; padding: 10px 14px;
  border-bottom: 1px solid var(--line-soft); background: var(--surface); }
.cards-flt__row { display: flex; align-items: flex-start; gap: 9px; min-width: 0; }
.cards-flt__lbl { flex: none; width: 56px; padding-top: 5px; font-family: var(--f-mono);
  font-size: 10px; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-faint); }
/* Chips WRAP here (the Events bar has three and lives on one line; this one has sixteen). */
.cards-flt .flt-chips { flex: 1 1 auto; flex-wrap: wrap; min-width: 0; }
.cards-flt .flt-chip { padding: 3px 9px; font-size: 11px; }
.cards-flt .flt-chip b.n { font-family: var(--f-mono); font-size: 10px; font-weight: 700; opacity: .7; }
/* A chip matching nothing right now is dimmed, never hidden: "0 declined" is an answer, and a bar
   whose chips appear and disappear between page loads can't be learned. Still clickable. */
.cards-flt .flt-chip.zero { opacity: .45; }
.cards-flt .flt-chip.on.zero { opacity: 1; }
.cards-flt__row--sel { flex-wrap: wrap; align-items: center; }
.cards-flt__row--sel select { flex: 0 1 186px; min-width: 0; padding-right: 26px; }
.cards-flt__row--sel select:disabled { opacity: .5; }
.cards-flt__row--sel .btn-mini { margin-left: auto; }
/* A history/expiry counter that means "the issuer said no" or "this is dead". */
.q-chip--bad { background: rgba(199, 62, 62, .08); border-color: var(--coral); color: var(--coral);
  font-weight: 700; }
/* Checkout-log error codes. A TM code (U103, U001, E101…) is Ticketmaster's own identifier; a
   WhaleRestocks label (BMP-BLOCK, NO-PROXY…) is OUR name for a failure TM described only in prose,
   or one that never reached TM. They must not look alike: reading 'NO-PROXY' as a TM code would
   send the operator hunting for a Ticketmaster error that does not exist. TM codes get the mono
   weight of a real identifier; ours are dimmer and dashed. */
.q-chip.code-tm { font-weight: 700; letter-spacing: .02em; }
.q-chip.code-ours { border-style: dashed; font-weight: 600; opacity: .92; }
/* The per-card log button is brighter when there IS a log to read. */
.icon-btn.has-log { color: var(--accent-deep); }
/* Log modal. Every cell is ONE line: the event name, the account email and TM's prose are all long
   enough to wrap a row to five lines each, which turns twenty attempts into a page nobody can scan.
   They clamp with an ellipsis instead and keep the full text in title= (the table scrolls
   horizontally inside its own wrapper, so nothing is unreachable). */
#cardLogBody .q-activity { margin: 0; }
#cardLogBody table.data td { vertical-align: middle; white-space: nowrap; }
#cardLogBody table.data th { white-space: nowrap; }
/* Event cell: the name on one line, the date / venue / seats under it. Two lines, both clamped, so
   every row stays the same height however long a tour name is. */
#cardLogBody .log-evcell { max-width: 230px; }
#cardLogBody .log-ev, #cardLogBody .log-ev__sub {
  display: block; max-width: 230px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#cardLogBody .log-ev__sub { font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-dim); }
/* Ticketmaster's own message is the primary evidence — give it the widest cell and let it take the
   remaining space rather than being the first thing pushed off the right edge. */
#cardLogBody .log-msg { max-width: 340px; min-width: 200px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
/* The log is a seven-column data table, not a form: at .modal.wide's 920px the message column — the
   whole point of the row — starts off-screen behind a horizontal scroll. Widen to fit it, still
   clamped to the viewport so it can never exceed the window (the phone rule below takes over at
   880px and makes every modal full-width anyway). */
#cardLogModal .modal.wide { max-width: min(1280px, calc(100vw - 48px)); }
/* An attempt where Ticketmaster never saw the card is context, not evidence about the card. */
#cardLogBody tr.log-unused > td { opacity: .62; }
#cardLogBody tr.log-unused .q-chip { opacity: 1; }

/* === shared cart/order card rows (used by the Carts + Orders pages) ======================= */
.card-rows{display:flex;flex-direction:column;gap:7px}
#cartGrid{display:flex;flex-direction:column;gap:7px}
.cart-row{padding:8px 13px;display:flex;flex-direction:column;gap:5px;line-height:1.2}
/* Orders live-filter: hide a card the search/window filter dropped (beats .cart-row's display:flex). */
.cart-row[hidden]{display:none}
/* Orders "showing N of M orders" count line under the toolbar. */
.orders-meta{margin:-2px 2px 12px;font-family:var(--f-mono);font-size:11.5px;color:var(--ink-dim)}
.cr-top{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.cr-id{min-width:0;flex:1 1 220px}
.cr-id h3{margin:0;font-size:13.5px;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cr-id .sub{margin-top:1px;display:flex;gap:6px;flex-wrap:wrap;align-items:center;font-size:10px;color:var(--ink-dim)}
.cr-facts{display:flex;gap:14px;flex:none;align-items:center}
.cr-status{display:flex;align-items:center;gap:8px;flex:none;margin-left:auto}
.ct-cell{min-width:0}
.ct-cell .k{font-size:8.5px;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-faint);font-family:var(--f-mono);line-height:1}
.ct-cell .v{font-size:12px;color:var(--ink);font-weight:600;margin-top:1px;font-variant-numeric:tabular-nums;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:130px;line-height:1.15}
.ct-cell .v.mono{font-family:var(--f-mono);font-weight:500}
.cr-bot{display:flex;align-items:center;gap:8px;flex-wrap:wrap;border-top:1px solid var(--line-soft);padding-top:6px}
.cr-meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0;flex:1 1 auto;font-size:11.5px}
.cr-ttype{font-weight:600;color:var(--ink)}
.cr-ttype .desc{font-weight:400;color:var(--ink-dim)}
/* TM delivery method (Mobile / Will Call / e-ticket) on a cart row. Long descriptions truncate —
   the full text is on the element's title attribute. */
.cr-deliv{display:inline-flex;align-items:center;gap:4px;font-weight:600;color:var(--ink);
  min-width:0;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cr-deliv .desc{font-weight:400;color:var(--ink-dim)}
.cr-deliv.muted{font-weight:400;color:var(--ink-dim)}
.cr-deliv.blocked{color:var(--bad,#c0392b)}
.cr-deliv-check{cursor:pointer;background:none;border:0;padding:0;font:inherit}
.cr-deliv-check[disabled]{opacity:.6;cursor:default}
/* Action group. Always a <fieldset> so a blocked cart can disable every control natively; reset the
   browser's default fieldset chrome so it lays out exactly as the old plain container did. */
.cr-actset{display:flex;align-items:center;gap:7px;flex-wrap:wrap;border:0;margin:0;padding:0;min-width:0}
/* A delivery-blocked (will call) hold: shown like every other cart, but visibly inert. */
.cart-blocked{opacity:.72}
.cart-blocked .cr-actset{opacity:.55;pointer-events:none}
.cr-note{font-family:var(--f-mono);font-size:10.5px;color:var(--ink-dim);min-width:0;max-width:340px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cr-note:empty{display:none}
.cr-note.co-live{font-family:inherit;font-size:11.5px;color:var(--sonar-deep);white-space:normal;
  max-width:none;overflow:visible}
.cr-note.co-result{font-family:inherit;font-size:11.5px;white-space:normal;max-width:none;
  overflow:visible;line-height:1.35;color:var(--ink-dim)}
.cr-note.co-result.good{color:var(--sonar-deep)}
.cr-note.co-result.bad{color:var(--coral)}
.cr-note.co-result.warn{color:var(--amber)}
.cr-note.co-result.info{color:var(--tide)}
.co-spin{display:inline-block;width:10px;height:10px;border:2px solid var(--line);
  border-top-color:var(--accent);border-radius:50%;animation:cospin .7s linear infinite;
  vertical-align:-1px;margin-right:6px}
@keyframes cospin{to{transform:rotate(360deg)}}
.cr-actions{display:flex;align-items:center;gap:7px;flex:none;margin-left:auto;flex-wrap:wrap}
.cr-cred{display:inline-flex;align-items:center;gap:5px;background:var(--deep);border:1px solid var(--line-soft);
  border-radius:var(--radius-sm);padding:2px 7px;min-width:0;max-width:220px}
.cr-cred>.ico{color:var(--ink-faint);flex:none;width:12px;height:12px}
.cr-cred .cv{font-family:var(--f-mono);font-size:11px;color:var(--ink);min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.brand-lead{font-size:9.5px;font-family:var(--f-mono);text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint)}
.brand-chips{display:inline-flex;align-items:center;gap:5px;flex-wrap:wrap}
.brand-chip{display:inline-flex;align-items:center;gap:4px;font-size:11px;font-family:var(--f-mono);font-weight:600;
  color:var(--ink-dim);border:1px solid var(--line);border-radius:999px;padding:2px 10px;background:var(--surface);
  cursor:pointer;transition:border-color .12s,background .12s,color .12s;user-select:none}
.brand-chip:hover{border-color:var(--accent);color:var(--accent-deep)}
.brand-chip.on{background:var(--accent-dim);border-color:var(--accent);color:var(--accent-deep)}
.brand-chip.on::before{content:"\2713";font-weight:700}
.ct-timer{display:inline-flex;align-items:center;gap:5px;font-family:var(--f-mono);font-size:11.5px;
  font-weight:600;padding:2px 8px;border-radius:999px;border:1px solid var(--line);
  background:var(--deep);color:var(--ink-dim);font-variant-numeric:tabular-nums;white-space:nowrap}
.ct-timer .ico{width:12px;height:12px}
.ct-timer.good{color:var(--sonar-deep);border-color:var(--sonar-glow);background:var(--sonar-dim)}
.ct-timer.warn{color:var(--amber);border-color:var(--amber-glow);background:var(--amber-glow)}
.ct-timer.bad{color:var(--coral);border-color:var(--coral-glow);background:var(--coral-glow);animation:ctpulse 1s ease-in-out infinite}
.ct-timer.expired{color:var(--ink-faint)}
@keyframes ctpulse{50%{opacity:.5}}
.ct-link{display:inline-flex;align-items:center;gap:4px;font-size:11px;font-family:var(--f-mono);
  color:var(--tide);text-decoration:none;border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:2px 8px;background:var(--surface);transition:border-color .15s,background .15s}
.ct-link:hover{border-color:var(--tide);background:var(--tide-glow)}
.ct-link .ico{width:12px;height:12px}
.ct-link.muted{color:var(--ink-ghost);border-style:dashed;cursor:default}
.ct-copy{flex:none;cursor:pointer;border:none;background:transparent;color:var(--ink-faint);
  padding:1px;border-radius:4px;display:inline-flex}
.ct-copy:hover{color:var(--accent);background:var(--accent-dim)}
.ct-copy .ico{width:12px;height:12px}
.cart-row .btn.sm{padding:5px 11px}
@media (max-width:760px){.cr-status{margin-left:0}.cr-actions{margin-left:0;width:100%}}

/* live event countdown (events page meta line) */
.countdown { font-family: var(--f-mono); font-size: 11px; color: var(--ink-faint); white-space: nowrap; }
.countdown.soon    { color: var(--amber); }                 /* < 24h */
.countdown.urgent  { color: var(--coral); font-weight: 600; } /* < 1h */
.countdown.started { color: var(--ink-faint); font-style: italic; }

/* =========================================================================================
   PURCHASES & SPEND — one-line ledger bar (Orders + Dashboard); window matrix collapsed
   behind the summary by default
   ========================================================================================= */
.spend summary { list-style: none; }
.spend summary::-webkit-details-marker { display: none; }
.spend__bar { display: flex; align-items: center; gap: 22px; padding: 11px 18px; cursor: pointer; user-select: none; }
.spend__title { display: inline-flex; align-items: center; gap: 9px; font-family: var(--f-display); font-weight: 700; font-size: 14px; color: var(--ink); flex: none; }
.spend__title .ico { width: 16px; height: 16px; color: var(--accent); }
.spend__cells { display: flex; align-items: center; gap: 36px; flex: 1; flex-wrap: wrap; min-width: 0; }
.spend__cell { display: flex; flex-direction: column; min-width: 0; }
.spend__label { font-family: var(--f-mono); font-size: 8.5px; letter-spacing: 1.3px; text-transform: uppercase; color: var(--ink-faint); }
.spend__num { font-family: var(--f-mono); font-weight: 600; font-size: 19px; letter-spacing: -.3px; color: var(--ink); margin-top: 2px; line-height: 1.1; }
.stat__sub.spend__sub { margin-top: 1px; font-size: 10px; color: var(--ink-faint); }
.spend__chev { display: inline-flex; align-items: center; gap: 8px; flex: none; font-size: 9.5px; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-faint); }
.spend__chev .token-panel__chev { width: 14px; height: 14px; transition: transform .16s; transform: rotate(90deg); }
.spend[open] .spend__chev .token-panel__chev { transform: rotate(-90deg); }
.spend__body { border-top: 1px solid var(--line-soft); }
.spend__matrix th:not(:first-child),
.spend__matrix td:not(:first-child) { text-align: right; }
.spend__matrix td:first-child { color: var(--ink); font-weight: 500; }

/* =========================================================================================
   DASHBOARD — slim stat strip + engine-instance rows
   ========================================================================================= */
.statline { display: grid; grid-template-columns: repeat(9, minmax(0, 1fr)); gap: 10px; margin-bottom: var(--gap); }
@media (max-width: 1500px) { .statline { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
@media (max-width: 1000px) { .statline { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .statline { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.stat.slim { padding: 10px 13px 9px; }
.stat.slim .stat__label { font-size: 8.5px; letter-spacing: 1.1px; gap: 5px; }
.stat.slim .stat__label .ico { width: 12px; height: 12px; }
.stat.slim .stat__value { font-size: 18px; margin-top: 5px; letter-spacing: -.3px; }
.stat.slim .stat__value .unit { font-size: 11px; margin-left: 2px; }
.stat.slim .stat__sub { margin-top: 3px; font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stat__off { font-size: 13px; }

.dash-split { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: var(--gap); align-items: start; }
/* Grid children default to min-width:auto, so the engine panel grew to its widest row instead of
   to the column. On a phone that pushed each .eng out to ~550px in a 390px viewport and, because
   the page clips horizontal overflow, silently CUT OFF the per-engine Update/Restart/Stop buttons
   — they were unreachable, not just ugly. Same fix as `.grid > *`. */
.dash-split > * { min-width: 0; }
@media (max-width: 1100px) { .dash-split { grid-template-columns: minmax(0, 1fr); } }
@media (min-width: 881px) { .dash-split .panel__body.flush { max-height: 440px; overflow-y: auto; } }

.eng-tools { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.eng-tools__btns { display: inline-flex; gap: 8px; flex: none; }
.dash-split .panel__head h2 { flex: none; white-space: nowrap; }
.eng-rows { display: flex; flex-direction: column; }
.eng { padding: 10px 16px 11px; border-bottom: 1px solid var(--line-soft); }
.eng:last-child { border-bottom: none; }
.eng__top { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; min-width: 0; }
.eng__state { flex: none; min-width: 78px; justify-content: center; }
.eng__name { font-weight: 600; color: var(--ink); font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 190px; }
.eng__meta { font-size: 10.5px; color: var(--ink-faint); min-width: 0; flex: 0 1 auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.eng__flag { font-size: 9.5px; padding: 1.5px 7px; flex: none; }
.eng__spacer { flex: 1; }
.eng__seen { font-size: 10.5px; color: var(--ink-faint); flex: none; }
.eng__actions { display: inline-flex; gap: 6px; flex: none; }
.eng__actions .ico { width: 14px; height: 14px; }
.icon-btn.is-warn { color: var(--amber); border-color: var(--amber-glow); background: rgba(176, 122, 16, .07); }
.icon-btn.is-good { color: var(--sonar-deep); border-color: var(--sonar-dim); background: var(--sonar-dim); }
.eng__bot { display: flex; align-items: center; gap: 9px; margin-top: 8px; flex-wrap: wrap; }
.eng__bot select { width: auto; min-width: 128px; max-width: 200px; padding: 5px 26px 5px 9px; font-size: 12px; }
table.data.compact th { padding: 8px 12px; }
table.data.compact td { padding: 7.5px 12px; }

/* =========================================================================================
   PAYOUTS — period stepper, ledger hero, partner cards, expense form
   ========================================================================================= */
.periodbar { display: inline-flex; align-items: center; gap: 2px; padding: 3px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface-2); }
.periodbar__nav { border: none; background: transparent; color: var(--ink-dim); width: 28px; height: 28px; border-radius: 5px; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; padding: 0; }
.periodbar__nav:hover { background: var(--surface); color: var(--ink); box-shadow: var(--shadow); }
.periodbar__nav .ico { width: 13px; height: 13px; }
.periodbar__nav.prev .ico { transform: rotate(180deg); }
.periodbar__label { min-width: 152px; text-align: center; font-family: var(--f-mono); font-weight: 600; font-size: 12.5px; color: var(--ink); }
.periodbar__custom { display: inline-flex; gap: 8px; align-items: center; }
.periodbar__custom[hidden] { display: none; }
.periodbar__custom .input { width: auto; padding: 6px 9px; font-size: 12.5px; }

.pay-partner .panel__head { padding: 12px 16px; }
.pay-partner .panel__body { padding: 6px 16px 12px; }
.pl-row { display: flex; justify-content: space-between; align-items: center; gap: 14px; padding: 7px 0; border-bottom: 1px solid var(--line-soft); font-size: 12.5px; color: var(--ink-dim); }
.pl-row:last-child { border-bottom: none; }
.pl-row .val { font-family: var(--f-mono); color: var(--ink); font-weight: 500; font-variant-numeric: tabular-nums; }

.exp-form { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; margin-bottom: 16px; }
.exp-f { display: block; margin: 0; }
.exp-f > span { display: block; font-family: var(--f-mono); font-size: 9px; letter-spacing: 1.2px; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 5px; }
.exp-f > span em { font-style: normal; text-transform: none; letter-spacing: 0; color: var(--ink-ghost); }
.exp-f .input { width: 100%; padding: 8px 11px; font-size: 13px; }
.exp-f--name { flex: 1 1 150px; min-width: 130px; }
.exp-f--descr { flex: 2 1 210px; min-width: 150px; }
.exp-f--amount { flex: 0 1 110px; }
.exp-f--type { flex: 0 1 132px; }
.exp-f--paidby { flex: 0 1 132px; }
.exp-f--date { flex: 0 1 150px; }
.exp-f--btns { display: flex; gap: 8px; flex: none; }
#expEndWrap[hidden] { display: none; }
table.data td.empty-row { text-align: center; color: var(--ink-faint); padding: 22px 14px; font-size: 12.5px; }

/* =========================================================================================
   SALES — resale ledger (hero P&L + sold-date window + sonar calendar)
   ========================================================================================= */
/* The toolbar owns a popover (the sold-date calendar) that has to paint over the ledger and the
   table below it, so it gets its own layer. 15 sits above page content (z-index auto) and below
   the sticky .fleet bar (20), which the popover should still scroll under. */
.toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: var(--gap); position: relative; z-index: 15; }

.rangebar { position: relative; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.rangebar__label { font-family: var(--f-mono); font-size: 10px; letter-spacing: 1.6px; text-transform: uppercase; color: var(--ink-faint); margin-right: 2px; }
.rangebar .chip-toggle { display: inline-flex; align-items: center; gap: 6px; }
.rangebar .chip-toggle .ico { width: 12px; height: 12px; }

/* live search — grows between the view toggle and the date range */
.sales-search { display: flex; align-items: center; gap: 7px; flex: 1 1 220px; min-width: 150px;
  max-width: 400px; padding: 0 11px; border: 1px solid var(--line-strong); border-radius: 99px;
  background: var(--surface-2); }
.sales-search:focus-within { border-color: var(--accent); background: var(--surface); }
.sales-search .ico { width: 14px; height: 14px; color: var(--ink-faint); flex: none; }
.sales-search input { flex: 1; min-width: 0; width: auto; border: none; background: transparent;
  padding: 8px 0; font-size: 13px; color: var(--ink); outline: none; }
.sales-search input::placeholder { color: var(--ink-ghost); }
.sales-search input::-webkit-search-cancel-button { -webkit-appearance: none; display: none; }
.sales-search__x { border: none; background: none; cursor: pointer; color: var(--ink-faint);
  padding: 2px; display: inline-flex; align-items: center; }
.sales-search__x:hover { color: var(--ink); }
.sales-search__x .ico { width: 13px; height: 13px; }

/* ---- ledger hero: the page's one loud element — profit for the selected window ---- */
.ledger { overflow: hidden; }
.ledger__grid { display: grid; grid-template-columns: minmax(300px, 1.15fr) 2fr; }
.ledger__hero {
  position: relative; padding: 24px 28px;
  border-right: 1px solid var(--line-soft);
  background: radial-gradient(130% 120% at 0% 0%, var(--accent-dim), transparent 62%);
}
.ledger__figure { font-family: var(--f-mono); font-weight: 600; font-size: clamp(32px, 3.6vw, 46px); letter-spacing: -1px; line-height: 1.05; margin-top: 10px; font-variant-numeric: tabular-nums; }
.ledger__figure.is-good { color: var(--sonar); }
.ledger__figure.is-bad  { color: var(--coral); }
.ledger__figure.is-warn { color: var(--amber); }
.ledger__figure.is-ink  { color: var(--ink); }
.ledger__sub { margin-top: 12px; font-family: var(--f-mono); font-size: 11.5px; color: var(--ink-dim); }
.ledger__sub b { color: var(--ink); font-weight: 600; }
.ledger__sub .is-good { color: var(--sonar-deep); }
.ledger__sub .is-warn { color: var(--amber); }
/* paid/pending refresh — a quiet pill sitting on the sub line beside the two figures it moves.
   Deliberately smaller and softer than a .btn: it belongs to the numbers, not to the page head. */
.ledger__refresh { display: inline-flex; align-items: center; gap: 5px; margin-left: 9px;
  padding: 2px 9px; border: 1px solid var(--line); border-radius: 99px; background: var(--surface-2);
  color: var(--ink-dim); font: inherit; font-size: 10.5px; line-height: 1.5; cursor: pointer;
  vertical-align: 1px; white-space: nowrap; }
.ledger__refresh:hover:not(:disabled) { color: var(--ink); border-color: var(--line-strong); }
.ledger__refresh:disabled { cursor: default; color: var(--ink-faint); }
.ledger__refresh.is-partial { color: var(--amber); border-color: var(--amber-glow); }
.ledger__refresh .ico { width: 11px; height: 11px; flex: none; }
.ledger__refresh .ico.spin { color: var(--accent); animation: spin .7s linear infinite; }
/* metric grid: column count comes from JS (cols-3 for 6 metrics, cols-2 for 2/4); hairlines
   between columns and rows only — the first column never doubles the hero's divider */
.ledger__metrics { display: grid; }
.ledger__metrics.cols-3 { grid-template-columns: repeat(3, 1fr); }
.ledger__metrics.cols-2 { grid-template-columns: repeat(2, 1fr); }
.ledger__m { padding: 18px 20px; border-left: 1px solid var(--line-soft); }
.ledger__metrics.cols-3 .ledger__m:nth-child(3n+1) { border-left: none; }
.ledger__metrics.cols-3 .ledger__m:nth-child(n+4) { border-top: 1px solid var(--line-soft); }
.ledger__metrics.cols-2 .ledger__m:nth-child(2n+1) { border-left: none; }
.ledger__metrics.cols-2 .ledger__m:nth-child(n+3) { border-top: 1px solid var(--line-soft); }
.ledger__m-label { font-family: var(--f-mono); font-size: 10px; letter-spacing: 1.6px; text-transform: uppercase; color: var(--ink-faint); }
.ledger__m-value { font-family: var(--f-mono); font-weight: 600; font-size: 19px; color: var(--ink); margin-top: 6px; font-variant-numeric: tabular-nums; }
.ledger__m-value.is-good { color: var(--sonar); }
.ledger__m-value.is-bad  { color: var(--coral); }
@media (max-width: 980px) {
  .ledger__grid { grid-template-columns: 1fr; }
  .ledger__hero { border-right: none; border-bottom: 1px solid var(--line-soft); }
  .ledger__metrics.cols-3 { grid-template-columns: repeat(2, 1fr); }
  .ledger__metrics.cols-3 .ledger__m:nth-child(3n+1) { border-left: 1px solid var(--line-soft); }
  .ledger__metrics.cols-3 .ledger__m:nth-child(2n+1) { border-left: none; }
  .ledger__metrics.cols-3 .ledger__m:nth-child(n+3) { border-top: 1px solid var(--line-soft); }
}

/* ---- token disclosure (rarely touched once saved) ---- */
.token-panel { margin-bottom: var(--gap); }
.token-panel summary { display: flex; align-items: center; gap: 9px; padding: 12px 18px; cursor: pointer; list-style: none; user-select: none; }
.token-panel summary::-webkit-details-marker { display: none; }
.token-panel summary .ico { width: 15px; height: 15px; color: var(--ink-faint); }
.token-panel__title { font-family: var(--f-display); font-weight: 600; font-size: 13px; color: var(--ink); }
.token-panel__chev { margin-left: auto; transition: transform .16s; transform: rotate(90deg); }
.token-panel[open] .token-panel__chev { transform: rotate(-90deg); }
.token-panel__body { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; border-top: 1px solid var(--line-soft); }
.token-panel__body input { flex: 1; min-width: 280px; width: auto; }

/* ---- account cell (Sales-page tabs): email + password, each copy-to-clipboard ---- */
.acct-cell { min-width: 150px; white-space: nowrap; }
.acct-line { display: flex; align-items: center; gap: 5px; max-width: 230px; }
.acct-line + .acct-line { margin-top: 3px; }
.acct-line > .ico { width: 12px; height: 12px; color: var(--ink-faint); flex: none; }
.acct-val { font-family: var(--f-mono); font-size: 11.5px; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acct-line .ct-copy { flex: none; }
.acct-line .ct-copy.ok { color: var(--sonar); }
.acct-line .ct-copy.ok .ico { color: var(--sonar); }

/* ---- Sales > Missing: per-row "Reset pw", stacked under the credentials it replaces ---- */
.rp-wrap { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; margin-top: 4px;
  max-width: 100%; }
.rp-btn { white-space: nowrap; flex: none; }
.rp-pill[hidden] { display: none; }
/* the status text can be a full reset error in one of the narrowest columns: ellipsize it and keep
   the whole thing in the pill's title */
.rp-pill { max-width: 100%; min-width: 0; overflow: hidden; }
.rp-pill .rp-pill-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- table note (unmatched-tickets warning under the sold table) ---- */
.sales-note { margin: 0 16px 12px; padding: 9px 12px; border-radius: var(--radius-sm); font-size: 12px;
  color: var(--amber); border: 1px solid var(--amber-glow); background: rgba(176, 122, 16, .06); }
.sales-note[hidden] { display: none; }

/* ---- P&L cell trimmings ---- */
.pnl-pct { font-size: 10.5px; opacity: .72; margin-left: 4px; }
.bundle-badge { font-family: var(--f-mono); font-size: 9.5px; letter-spacing: .4px; text-transform: uppercase;
  color: var(--accent-deep); background: var(--accent-dim); border: 1px solid var(--accent-dim);
  border-radius: 99px; padding: 1px 6px; margin-left: 6px; vertical-align: middle; }
/* backfilled = event details came from our own order, not Lysted (amber, to read as "our data") */
.bundle-badge.bf { color: var(--amber); background: rgba(176, 122, 16, .08); border-color: var(--amber-glow); }
/* cancelled = event cancelled & refunded — row stays visible but counts in NO number (coral) */
.bundle-badge.cx { color: var(--coral); background: rgba(210, 59, 76, .07); border-color: var(--coral-glow); }
/* edited = hand-corrected by the operator; the override is permanent and drives every number */
.bundle-badge.ed { color: var(--ink-dim); background: var(--surface-2); border-color: var(--line-soft); }
tr.is-cancelled td { opacity: .55; }
/* written off = booked as a $0 sale. Dimmed like a cancelled row, but struck through on the money
   columns so it never reads as a trade that simply went badly. */
tr.is-loss td { opacity: .62; }
tr.is-loss td.num { text-decoration: line-through; text-decoration-thickness: 1px; }
/* a Sec/Row/Seats value we filled from our own cart rather than Lysted */
.is-backfilled { border-bottom: 1px dotted var(--amber-glow); }
.act-cell { text-align: right; white-space: nowrap; }
.act-cell .icon-btn { font-size: 11px; line-height: 1; padding: 3px 5px; }
.act-cell .icon-btn + .icon-btn { margin-left: 1px; }
.icon-btn.warn:hover { color: var(--amber); border-color: var(--amber-glow); }

/* ---- Sales ledger table: fits the panel at every width, never scrolls sideways ----
   The four views run 13-15 columns. Rather than let the table set its own intrinsic width (which
   overflows .table-wrap and grows a horizontal scrollbar), it is table-layout:fixed and sales.js
   emits a <colgroup> whose percentages sum to 100 — so the table is exactly the panel width, at
   any viewport. Values that don't fit ellipsize and keep their full text in a title tooltip. */
#salesTable { table-layout: fixed; width: 100%; font-size: 12.5px; }
/* Tighter gutters than the generic .data table: with 15 columns every saved pixel goes into
   keeping a money figure whole rather than ellipsized. */
#salesTable th, #salesTable td {
  padding-left: 6px; padding-right: 6px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#salesTable th:first-child, #salesTable td:first-child { padding-left: 12px; }
/* The action / PO cells hold real controls, so they get their own tighter box — and they stay
   `overflow: hidden` like every other cell. A visible overflow here is what grew the wrapper's
   scrollWidth past the table (the buttons spilled out of the last column), which is exactly the
   horizontal scrollbar this layout exists to prevent. */
#salesTable td.act-cell, #salesTable th:last-child { padding-left: 4px; padding-right: 6px; }
#salesTable td.act-cell .icon-btn { padding: 2px 4px; }
/* Wrap instead of clip: when the column gets tight the buttons drop to a second line inside the
   cell — still fully clickable, and the cell still can't widen the table. */
#salesTable td.act-cell, #salesTable td.po-cell { white-space: normal; }
#salesTable td.po-cell .po-wrap { display: inline-flex; align-items: center; gap: 3px;
  flex-wrap: wrap; max-width: 100%; }
#salesTable td.po-cell .btn.sm { padding: 3px 7px; font-size: 10.5px; white-space: nowrap; }
/* the account cell stacks email + password, each ellipsizing inside the column */
#salesTable .acct-cell { min-width: 0; }
#salesTable .acct-line { max-width: 100%; }
/* …and, on Missing, a Reset pw control under them — same compact button metrics as the PO column,
   and the cell has to allow wrapping or the button + its status pill can't drop to a second line */
#salesTable td.acct-cell { white-space: normal; }
#salesTable td.acct-cell .btn.sm { padding: 3px 7px; font-size: 10.5px; white-space: nowrap; }
/* the event cell holds a name plus badges — let the badges keep their size and the name give way */
#salesTable td .ev-name { display: inline-block; max-width: 100%; overflow: hidden;
  text-overflow: ellipsis; vertical-align: bottom; }
/* compact pill: the status column is one of the narrowest, and a full-size pill (dot + 11px text
   + 14px gutters) is what made "COMPLETE" ellipsize. */
#salesTable td .pill { font-size: 9.5px; padding: 2px 6px; gap: 4px; }
#salesTable td .pill .dot { width: 4px; height: 4px; }
/* Below 1700px the P&L column can't hold "▼ $260.00 -100%" — drop the secondary ROI suffix so the
   MONEY is always whole. The full "amount · ROI" stays in the cell's title. */
@media (max-width: 1700px) { #salesTable .pnl-pct { display: none; } }

/* edit-row / edit-order modal: two columns of short fields, and JS hides the ones that don't
   apply to the row being edited (a sale has cost/payout/sold-to; an order has $ per ticket). */
.edit-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.edit-grid .add-field[hidden] { display: none; }

/* ---- add-order modal ---- */
.add-help { font-size: 13px; color: var(--ink-dim); margin-bottom: 16px; line-height: 1.5; }
.add-field { display: block; margin-bottom: 14px; }
.add-field > span { display: block; font-family: var(--f-mono); font-size: 10px; letter-spacing: 1.4px;
  text-transform: uppercase; color: var(--ink-faint); margin-bottom: 6px; }
.add-field > span em { font-style: normal; text-transform: none; letter-spacing: 0; color: var(--ink-ghost); }
.add-field .input { width: 100%; }
.add-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.add-result { margin-top: 4px; padding: 10px 12px; border-radius: var(--radius-sm); font-size: 12.5px;
  border: 1px solid var(--line-soft); background: var(--surface-2); }
.add-result.is-good { color: var(--sonar-deep); border-color: var(--sonar-dim); background: var(--sonar-dim); }
.add-result.is-warn { color: var(--amber); border-color: var(--amber-glow); background: rgba(176, 122, 16, .06); }
.add-result[hidden] { display: none; }
.add-manual { margin-top: 18px; }
.add-manual__title { font-family: var(--f-mono); font-size: 10px; letter-spacing: 1.4px; text-transform: uppercase;
  color: var(--ink-faint); margin-bottom: 8px; }
.add-manual__row { display: flex; align-items: center; gap: 10px; padding: 7px 0; border-top: 1px solid var(--line-soft); font-size: 12.5px; }
.add-manual__row .mono { color: var(--ink); font-family: var(--f-mono); }
.add-manual__meta { color: var(--ink-faint); font-size: 11.5px; margin-right: auto; }

/* ---- cancelled-events modal ---- */
.cancel-list { max-height: 340px; overflow-y: auto; border: 1px solid var(--line-soft); border-radius: 8px; }
.cancel-row { display: flex; align-items: center; gap: 12px; padding: 9px 12px; border-top: 1px solid var(--line-soft); }
.cancel-row:first-child { border-top: 0; }
.cancel-row__info { min-width: 0; margin-right: auto; }
.cancel-row__name { font-size: 13px; color: var(--ink); }
.cancel-row__meta { font-size: 11.5px; color: var(--ink-faint); margin-top: 2px; }
.cancel-row.is-cancelled .cancel-row__name { text-decoration: line-through; opacity: .6; }
.cancel-row .btn { flex: none; white-space: nowrap; }
/* dimmed Orders card for a cancelled (refunded) order — visible, badged, counts for nothing */
.cart-row.is-cancelled .cr-top, .cart-row.is-cancelled .cr-bot { opacity: .55; }

/* ---- run rate: the window's profit carried out to a day / week / month / year average ---- */
.runrate { margin-top: var(--gap); overflow: hidden; }
.runrate__head {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  padding: 13px 20px; border-bottom: 1px solid var(--line-soft);
}
.runrate__title { font-family: var(--f-mono); font-size: 10px; letter-spacing: 1.6px; text-transform: uppercase; color: var(--ink-faint); }
.runrate__basis { font-family: var(--f-mono); font-size: 11px; color: var(--ink-dim); }
.runrate__basis b { color: var(--ink); font-weight: 600; }
.runrate__grid { display: grid; grid-template-columns: repeat(4, 1fr); }
.runrate__c { padding: 16px 20px; border-left: 1px solid var(--line-soft); }
.runrate__c:first-child { border-left: none; }
.runrate__label { font-family: var(--f-mono); font-size: 10px; letter-spacing: 1.6px; text-transform: uppercase; color: var(--ink-faint); }
.runrate__v { font-weight: 600; font-size: 22px; letter-spacing: -.3px; margin-top: 7px; }
.runrate__v.is-good { color: var(--sonar); }
.runrate__v.is-bad  { color: var(--coral); }
.runrate__sub { font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-faint); margin-top: 5px; }
@media (max-width: 880px) {
  .runrate__grid { grid-template-columns: repeat(2, 1fr); }
  .runrate__c:nth-child(2n+1) { border-left: none; }
  .runrate__c:nth-child(n+3) { border-top: 1px solid var(--line-soft); }
}

/* ---- sonar calendar popover (custom sold-date range: two clicks) ---- */
.cal {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60; width: 264px;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: 0 12px 32px -12px rgba(16, 24, 40, .18); padding: 12px;
}
.cal__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.cal__title { font-family: var(--f-mono); font-size: 11.5px; font-weight: 600; letter-spacing: .6px; color: var(--ink); }
.cal__nav {
  width: 26px; height: 26px; border-radius: var(--radius-sm); border: 1px solid var(--line);
  background: var(--surface-2); color: var(--ink-dim); font-size: 14px; line-height: 1; cursor: pointer;
}
.cal__nav:hover { border-color: var(--accent-glow); color: var(--ink); }
.cal__dow { display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 3px; }
.cal__dow span { text-align: center; font-family: var(--f-mono); font-size: 9px; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-ghost); padding: 3px 0; }
.cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal__day {
  height: 30px; border: none; border-radius: var(--radius-sm); background: transparent;
  font-family: var(--f-mono); font-size: 11.5px; color: var(--ink-dim); cursor: pointer;
  font-variant-numeric: tabular-nums; padding: 0;
}
.cal__day:hover { background: var(--surface-3); color: var(--ink); }
.cal__day.is-out { color: var(--ink-ghost); }
.cal__day.is-off { opacity: .3; cursor: not-allowed; }
.cal__day.is-today { box-shadow: inset 0 0 0 1px var(--line-strong); }
.cal__day.is-in { background: var(--accent-dim); color: var(--accent-deep); border-radius: 0; }
.cal__day.is-start, .cal__day.is-end {
  background: var(--accent); color: #fff; font-weight: 600;
}
.cal__day.is-start { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.cal__day.is-end { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.cal__day.is-start.is-end { border-radius: var(--radius-sm); }
.cal__foot { margin-top: 9px; padding-top: 8px; border-top: 1px solid var(--line-soft); font-family: var(--f-mono); font-size: 10px; letter-spacing: .4px; color: var(--ink-faint); text-align: center; }
@media (max-width: 560px) { .cal { right: auto; left: 0; } }

/* =========================================================================================
   Seat map, shared by Restocks and Explorer
   ========================================================================================= */
  .sm-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:6px;flex-wrap:wrap}
  .sm-btn{font-family:var(--f-mono);font-size:13px;font-weight:600;line-height:1;color:var(--ink-dim);
    border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--surface);padding:5px 11px;cursor:pointer}
  .sm-btn:hover{border-color:var(--sonar);color:var(--sonar-deep)}
  .sm-hint{font-size:11px;color:var(--ink-faint)}
  .sm-wrap{position:relative;width:100%;height:68vh;min-height:460px;overflow:hidden;
    border:1px solid var(--line);border-radius:var(--radius);background:var(--surface-2)}
  .sm-svg{width:100%;height:100%;display:block;cursor:grab;touch-action:none}
  .sm-svg.grabbing{cursor:grabbing}
  .sm-sec{fill:var(--surface-3);stroke:var(--line);stroke-width:6}
  .sm-seat{stroke:#fff;stroke-width:1.5}
  .sm-open{fill:var(--sonar)}
  .sm-taken{fill:var(--ink-ghost);opacity:.5}
  .sm-legend{display:inline-flex;align-items:center;gap:6px;margin-left:auto;font-size:12px;color:var(--ink-dim)}
  .sm-dot{width:10px;height:10px;border-radius:99px;display:inline-block;margin-left:8px}
  .sm-dot.sm-open{background:var(--sonar)}
  .sm-dot.sm-taken{background:var(--ink-ghost)}
  .sm-tip{position:absolute;z-index:5;pointer-events:none;background:var(--ink);color:#fff;font-size:11.5px;
    line-height:1.4;padding:6px 9px;border-radius:6px;max-width:240px;box-shadow:var(--shadow);white-space:pre-line}
  .sm-tip[hidden]{display:none}

/* =========================================================================================
   MOBILE / PHONE  — comprehensive touch + small-screen treatment
   The console renders full-screen inside the WhaleRestocks iOS WebView (no browser chrome),
   so this layer owns: safe-area insets (notch / home indicator), 16px inputs (iOS zooms
   anything smaller on focus), >=44px tap targets, no page-level horizontal scroll (wide
   tables become stacked cards), bottom-sheet modals, and full-width toasts.
   ========================================================================================= */

/* --- safe-area insets: the sticky chrome must clear the notch / home indicator --- */
.fleet   { padding-top: max(9px, env(safe-area-inset-top)); padding-left: max(22px, env(safe-area-inset-left)); padding-right: max(22px, env(safe-area-inset-right)); }
.rail    { padding-top: env(safe-area-inset-top); }
.toasts  { bottom: max(18px, env(safe-area-inset-bottom)); right: max(18px, env(safe-area-inset-right)); }

/* Kill page-level horizontal scroll: nothing should push the body wider than the phone.
   Wide content (tables, code, maps) scrolls inside its OWN container, never the page. */
@media (max-width: 880px) {
  /* overflow-x: clip (not hidden) — clip does NOT become a scroll container, so it can't
     change the sticky-positioning context of the .fleet HUD the way `hidden` can. */
  html, body { max-width: 100%; overflow-x: clip; }
  .main { min-width: 0; max-width: 100%; overflow-x: clip; }
  .content { padding: 18px max(14px, env(safe-area-inset-left)) calc(60px + env(safe-area-inset-bottom)) max(14px, env(safe-area-inset-right)); }

  /* readable inputs: 16px prevents iOS focus-zoom; roomy padding = a real tap target */
  input[type=text], input[type=password], input[type=number], input[type=search],
  input[type=url], input[type=email], select, textarea { font-size: 16px; padding: 11px 13px; }
  .inp-mini { width: 72px; font-size: 16px; padding: 7px 9px; }
  .sel-mini { font-size: 16px; padding: 7px 26px 7px 10px; }

  /* >=44px tap targets across every interactive control */
  .btn { min-height: 44px; padding: 10px 16px; }
  .btn.sm { min-height: 40px; }
  .icon-btn { min-width: 40px; min-height: 40px; align-items: center; justify-content: center; }
  .toggle { min-height: 34px; padding: 6px 12px; }
  .checkbox input, .pick input, input[type=checkbox], input[type=radio] { width: 20px; height: 20px; }
  a.reveal, .ct-copy, .modal__close { min-width: 40px; min-height: 40px; }
  .ct-copy, .modal__close { display: inline-flex; align-items: center; justify-content: center; }

  /* fleet HUD: title + hamburger on one line, status chips scroll as one row below */
  .fleet { gap: 8px; padding-top: max(8px, env(safe-area-inset-top)); padding-bottom: 8px; }
  .fleet__title { margin-right: auto; }
  .fleet__clock { display: none; }              /* the phone shows its own clock */
  #fleetStrip {
    order: 3; flex: 0 0 100%; flex-wrap: nowrap; overflow-x: auto;
    -webkit-overflow-scrolling: touch; scrollbar-width: none; padding-bottom: 2px;
  }
  #fleetStrip::-webkit-scrollbar { display: none; }
  #fleetStrip .chip { flex: none; }

  /* page header stacks; actions become a full-width wrapping button row */
  .page-head { flex-direction: column; align-items: stretch; gap: 14px; margin-bottom: 18px; }
  .page-head__r { flex-wrap: wrap; }
  .page-head__r .btn { flex: 1 1 auto; }
  h1 { font-size: 22px; }
  .page-head p { font-size: 13px; }
  .toolbar { gap: 10px; }
  .btn-row .btn { flex: 1 1 auto; }
}

/* --- command-rail drawer: a tap-scrim behind the open rail closes it (added by console.js) --- */
.rail-scrim {
  position: fixed; inset: 0; z-index: 55; background: rgba(20, 30, 45, .38);
  backdrop-filter: blur(2px); opacity: 0; pointer-events: none; transition: opacity .2s;
}
.rail-scrim.show { opacity: 1; pointer-events: auto; }
@media (max-width: 880px) {
  .rail {
    width: min(86vw, 320px); box-shadow: 0 0 40px -8px rgba(16,24,40,.4);
    padding-bottom: env(safe-area-inset-bottom); background: var(--surface);
  }
  /* Roomier drawer: 44px rows, bigger glyphs, and a real dismiss in the brand bar. */
  .rail__brand { padding: 14px 14px 13px; }
  .rail__close {
    display: inline-flex; align-items: center; justify-content: center;
    margin-left: auto; flex: none;
    width: 40px; height: 40px; border-radius: 999px;
    border: 1px solid var(--line); background: var(--surface); color: var(--ink-faint);
    cursor: pointer; padding: 0;
  }
  .rail__close:active { background: var(--surface-2); }
  .rail__close .ico { width: 17px; height: 17px; }
  .rail__nav { padding: 6px 10px 18px; gap: 2px; }
  .rail__group { font-size: 9.5px; margin: 15px 0 6px; }
  .navlink { padding: 11px 12px; font-size: 15px; min-height: 44px; border-radius: 9px; }
  .navlink svg { width: 19px; height: 19px; }
  .navlink.is-active::before { left: -10px; height: 22px; }
  .navlink__badge { font-size: 12px; }
  .rail__instance { padding: 12px 14px; }
  .rail__pick select { font-size: 16px; padding: 10px 26px 10px 8px; }
  .rail__foot { padding: 12px 14px calc(12px + env(safe-area-inset-bottom)); }
  .rail__out { min-height: 40px; font-size: 13.5px; }
}

/* =========================================================================================
   MOBILE TABLES → STACKED CARDS
   Every data table becomes label/value cards at phone width so nothing scrolls sideways.
   console.js stamps each <td> with data-label from its column header. A table that must
   stay columnar can opt out with class "no-cards" (it then scrolls inside .table-wrap).
   ========================================================================================= */
@media (max-width: 640px) {
  .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

  table.data:not(.no-cards) { font-size: 14px; }
  table.data:not(.no-cards) thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  table.data:not(.no-cards),
  table.data:not(.no-cards) tbody,
  table.data:not(.no-cards) tr,
  table.data:not(.no-cards) td { display: block; width: auto; }
  table.data:not(.no-cards) tr {
    border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
    margin-bottom: 10px; padding: 2px 0; box-shadow: var(--shadow);
  }
  table.data:not(.no-cards) tbody tr:hover { background: var(--surface); }
  table.data:not(.no-cards) td {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    padding: 9px 14px; border-bottom: 1px solid var(--line-soft);
    white-space: normal; text-align: right; min-height: 40px;
  }
  table.data:not(.no-cards) tr td:last-child { border-bottom: none; }
  table.data:not(.no-cards) td::before {
    content: attr(data-label); flex: none; text-align: left;
    font-family: var(--f-mono); font-size: 9.5px; letter-spacing: 1px; text-transform: uppercase;
    color: var(--ink-faint); font-weight: 500;
  }
  /* a cell with no header label (e.g. the row-actions column) spans full width, no gutter */
  table.data:not(.no-cards) td[data-label=""]::before,
  table.data:not(.no-cards) td:not([data-label])::before { content: none; }
  table.data:not(.no-cards) td[data-label=""],
  table.data:not(.no-cards) td:not([data-label]) { justify-content: flex-end; flex-wrap: wrap; }
  table.data:not(.no-cards) td.num { text-align: right; }
  /* let action buttons inside a card cell breathe */
  table.data:not(.no-cards) td .btn,
  table.data:not(.no-cards) td .btn.sm { min-height: 38px; }
}

/* Card layout hides each table's thead — and with it any select-all checkbox that lives
   there (events). .mob-selectall is a stand-in bar above the table, phone width only. */
.mob-selectall { display: none; }
@media (max-width: 640px) {
  .mob-selectall {
    display: flex; align-items: center;
    padding: 10px 14px; border-bottom: 1px solid var(--line-soft);
  }
  /* the card layout only visually clips the <thead>; its #selAll checkbox stays in the
     focus order + a11y tree. Drop it on phones so there's exactly ONE select-all control
     (the .mob-selectall bar above) — syncBulk still updates it fine while display:none. */
  #selAll { display: none; }
}

/* =========================================================================================
   MOBILE MODALS → BOTTOM SHEETS
   Full-width, bottom-anchored, slide up. Body scrolls; header/footer pinned. Foot buttons
   go full-width so a thumb can hit them. Applies to every .modal-backdrop/.modal on the site.
   ========================================================================================= */
@media (max-width: 640px) {
  .modal-backdrop { align-items: flex-end; padding: 0; }
  .modal, .modal.wide {
    max-width: 100%; width: 100%; max-height: 92vh;
    border-radius: 18px 18px 0 0; border-bottom: none;
    animation: sheet-up .26s cubic-bezier(.2,.7,.3,1) both;
    padding-bottom: env(safe-area-inset-bottom);
  }
  .modal__head { padding: 16px 18px; position: sticky; top: 0; background: var(--surface); z-index: 2; border-radius: 18px 18px 0 0; }
  .modal__head::before { content: ""; position: absolute; top: 6px; left: 50%; transform: translateX(-50%); width: 38px; height: 4px; border-radius: 99px; background: var(--line-strong); }
  .modal__body { padding: 16px 18px; -webkit-overflow-scrolling: touch; }
  .modal__foot { flex-direction: column-reverse; align-items: stretch; gap: 8px; padding: 14px 18px calc(14px + env(safe-area-inset-bottom)); position: sticky; bottom: 0; background: var(--surface); }
  .modal__foot .btn { width: 100%; }
  @keyframes sheet-up { from { transform: translateY(100%); } }

  /* pickers: taller rows, bigger radios */
  .pick { padding: 13px; min-height: 52px; }
  .pick-list { max-height: 52vh; }

  /* curate / seat-map modal stacks; the map gets real height and pinch/scroll room */
  .cur-grid { grid-template-columns: 1fr; }
  .seatmap-wrap { max-height: 44vh; }
  .sm-wrap { height: 56vh; min-height: 320px; }
  .sm-toolbar { gap: 6px; }
  .sm-legend { margin-left: 0; }

  /* sold-date calendar popover becomes a centered sheet, not an off-screen dropdown */
  .cal { position: fixed; left: 12px; right: 12px; top: auto; bottom: calc(12px + env(safe-area-inset-bottom)); width: auto; }
  .cal__day { height: 40px; }
}

/* --- toasts: full-width along the bottom on phones so they never clip off-screen --- */
@media (max-width: 640px) {
  .toasts { left: max(12px, env(safe-area-inset-left)); right: max(12px, env(safe-area-inset-right)); max-width: none; }
  .toast { font-size: 14px; }
}

/* =========================================================================================
   MOBILE — per-page / per-component fixes (layered on the foundation above)
   ========================================================================================= */
@media (max-width: 880px) {
  /* Any panel/summary header with actions opposite its title wraps instead of overflowing.
     The action group (often an inline-styled classless div) drops to its own full-width row. */
  .panel__head { flex-wrap: wrap; }
  .panel__head > div:not(.sub), .panel__head > form, .panel__head > .row, .panel__head .btn-row { flex-wrap: wrap; }
  .panel__head > .row[style] { flex-wrap: wrap !important; }        /* override inline nowrap */
  summary.panel__head { flex-wrap: wrap; }

  /* big mono figures shrink so they never blow out a 1-col card */
  .stat__value { font-size: 25px; }
  .ledger__figure { font-size: clamp(30px, 9vw, 40px); }

  /* Dashboard "Update all / Restart all / …" and any fleet-wide action group: full-width row */
  .panel__head > div[style*="display:flex"] { width: 100%; justify-content: flex-start; }
}

@media (max-width: 640px) {
  /* --- Explorer keeps its dense reference/analytics tables columnar (contained scroller) --- */
  .xp-table-wrap { -webkit-overflow-scrolling: touch; }
  .xp-table-wrap table.data { display: table; width: 100%; font-size: 12px; }
  .xp-table-wrap table.data thead { display: table-header-group; position: static; width: auto; height: auto; overflow: visible; clip: auto; }
  .xp-table-wrap table.data tbody { display: table-row-group; }
  .xp-table-wrap table.data tr { display: table-row; margin: 0; padding: 0; border: 0; border-radius: 0; box-shadow: none; background: none; }
  .xp-table-wrap table.data td { display: table-cell; min-height: 0; text-align: left; white-space: nowrap; }
  .xp-table-wrap table.data td::before { content: none; }
  .xp-table-wrap table.data td.num { text-align: right; }

  /* --- Explorer header + seat-map color-mode segment: stack and scroll, don't overflow --- */
  .xp-map-head { flex-direction: column; align-items: stretch; gap: 10px; }
  .xp-segment { overflow-x: auto; flex-wrap: nowrap; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .xp-segment::-webkit-scrollbar { display: none; }
  .xp-segment button { flex: none; min-height: 40px; }
  .page-head__r.xp-controls, #xpControls { width: 100%; }
  .xp-input, #xpInput { width: 100%; }

  /* --- Carts / Orders: the 6-cell fact strip becomes a 3-up labelled mini-grid --- */
  .cr-facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px 12px; width: 100%; }
  .cr-facts .ct-cell { min-width: 0; }
  .ct-cell .v { max-width: 100%; }
  .ct-cell .k { font-size: 9.5px; }
  .cr-top, .cr-bot { row-gap: 8px; }
  .cr-actions { margin-left: 0; width: 100%; }
  .cr-actions [data-checkout], .cr-actions [data-pickacct] { flex: 1 1 100%; order: -1; }   /* primary action on top, full width */
  /* A BOUND cart keeps Pick/Random account alongside Run checkout (retry on a different account).
     Run checkout stays the full-width primary on top; the two ghost buttons then share the row
     below it instead of stacking into a three-button tower. `flex: 1 1 0` splits the line evenly
     whatever the gap is. */
  .cr-actions [data-checkout] ~ [data-pickacct],
  .cr-actions [data-checkout] ~ [data-randacct] { flex: 1 1 0; order: 0; min-width: 0; }
  .cr-cred { max-width: 100%; }
  .event-group-header { flex-wrap: wrap; }
  .egh-artist { max-width: 100%; }
  .egh-meta { min-width: 0; flex-shrink: 1; }

  /* --- Carts "Pick an account" rows stack instead of crushing the email --- */
  .pa-acct { flex-wrap: wrap; }
  .pa-acct .em { min-width: 0; flex: 1 1 100%; }
  .pa-acct .pa-note { min-width: 0; }
  .pa-acct .btn { flex: 1 1 100%; }

  /* --- Warm pool header row wraps; the flex spacer collapses so controls stay on screen --- */
  .row .fleet__spacer { display: none; }
  .wp-acct .em { min-width: 0; }

  /* --- Settings save bar: clear the home indicator, full-width buttons, drop the label --- */
  .savebar { padding-bottom: calc(14px + env(safe-area-inset-bottom)); }
  .savebar .muted.mono { display: none; }
  .savebar .btn-row { flex: 1; }
  .savebar .btn-row .btn { flex: 1; }

  /* --- Sales token field must not force page-width; view/range chips get real targets --- */
  .token-panel__body input { min-width: 0; }
  #salesViews .chip-toggle, #salesRange .chip-toggle, .rangebar .chip-toggle { min-height: 38px; }

  /* --- Logs: tab strips scroll horizontally as one row; taller tab targets --- */
  .tabs, .ilog-bar { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .tabs::-webkit-scrollbar, .ilog-bar::-webkit-scrollbar { display: none; }
  .tabs .tab, .ilog-bar .tab { flex: none; min-height: 40px; display: inline-flex; align-items: center; }
  /* card-ified log cells: let the message/reason columns wrap full width */
  table.data:not(.no-cards) td[style*="max-width"] { max-width: none !important; }

  /* --- Events: bulk bar + filter row wrap; curate chips are comfortable targets --- */
  #bulkBar { flex-wrap: wrap; gap: 8px; }
  #bulkBar .row { flex-wrap: wrap; }
  .chip-toggle, .flt-chip { min-height: 34px; }

  /* --- Login (its own template, does not extend base) — safe-area + no on-load zoom --- */
  .gate { min-height: 100dvh; padding: max(24px, env(safe-area-inset-top)) max(20px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom)) max(20px, env(safe-area-inset-left)); }
}

/* ── shared explorer visual language (moved verbatim from explorer.html; used by Explorer + Restocks) ── */
.xp-statrow{display:grid;grid-template-columns:repeat(auto-fit,minmax(138px,1fr));gap:10px;margin:0 0 16px}
.xp-statrow .stat{padding:14px 14px 13px}
.xp-statrow .stat__value{font-size:24px;letter-spacing:-.25px}
.xp-flash{animation:xp-stat-flash .55s ease-out}
@keyframes xp-stat-flash{0%{background:var(--sonar-dim)}100%{background:transparent}}
.xp-map-panel{margin-bottom:16px}
.xp-head-tools{display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:flex-end}
.xp-segment{display:inline-flex;align-items:center;gap:2px;padding:2px;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--surface-2)}
.xp-segment button{border:none;background:transparent;color:var(--ink-dim);font-family:var(--f-mono);font-size:10.5px;
  font-weight:600;padding:5px 8px;border-radius:5px;cursor:pointer}
.xp-segment button:hover{color:var(--ink)}
.xp-segment button.on{background:var(--surface);color:var(--sonar-deep);box-shadow:var(--shadow)}
.xp-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px}
.xp-grid>*{min-width:0}
@media (max-width:1100px){.xp-grid{grid-template-columns:1fr}}
.xp-panel-tall .panel__body{min-height:276px}
.xp-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.xp-filter{max-width:220px;font-size:12px;padding:7px 10px}
.xp-table-wrap{overflow:auto;max-height:330px}
.xp-sec-table tbody tr{cursor:pointer}
.xp-sec-table tbody tr.is-selected{background:var(--sonar-dim)}
.xp-sec-table th{cursor:pointer;user-select:none}
.xp-sec-table th.on{color:var(--sonar-deep)}
.xp-badge{display:inline-flex;align-items:center;max-width:100%;border:1px solid var(--line);border-radius:999px;
  padding:2px 7px;background:var(--surface-2);font-family:var(--f-mono);font-size:10.5px;color:var(--ink-dim)}
.xp-badge.good{border-color:var(--sonar-dim);background:var(--sonar-dim);color:var(--sonar-deep)}
.xp-badge.bad{border-color:var(--coral-glow);background:rgba(210,59,76,.06);color:var(--coral)}
.xp-trunc{display:block;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.xp-trunc-wide{max-width:420px}
.xp-link{display:inline-block;margin-left:6px;font-family:var(--f-mono);font-size:10.5px;color:var(--sonar-deep);text-decoration:none}
.xp-link:hover{text-decoration:underline}
/* Two "this number isn't the whole story" markers, both Explorer-only: a price-ladder zone holding
   more than one price (the seat-level "PLAT" bucket above all), and a GA pool showing the last
   price seen before it sold out — GA prices live only in the push, so they vanish on sell-out. */
.xp-badge-spread{margin-left:6px;border-color:var(--sonar-dim);background:var(--sonar-dim);color:var(--sonar-deep)}
.xp-badge-stale{margin-left:6px;border-style:dashed}
.xp-row-stale td{opacity:.62}
/* "TM published no price for this section" — deliberately distinct from a bare "—", which on this
   tab means "we don't know" (catalog failed to load). */
.xp-na{font-family:var(--f-mono);font-size:10.5px;color:var(--ink-dim);font-style:italic}

/* ── mobile: dashboard engine rows / spend bar / payouts form ── */
@media (max-width: 880px) {
  .eng-tools { width: 100%; justify-content: flex-start; }
  .eng-tools__btns { flex-wrap: wrap; }
}
@media (max-width: 640px) {
  .spend__bar { flex-wrap: wrap; gap: 10px 12px; }
  .spend__title { flex: 1 1 auto; }
  .spend__chev { margin-left: auto; order: 2; }
  .spend__cells { order: 3; flex: 1 1 100%; justify-content: space-between; gap: 12px; }
  .spend__num { font-size: 17px; }
  .eng__name { max-width: 130px; }
  .eng__actions .icon-btn { min-width: 40px; min-height: 40px; }
  .periodbar__label { min-width: 112px; }
  .exp-f--name, .exp-f--descr, .exp-f--amount, .exp-f--type, .exp-f--paidby, .exp-f--date { flex: 1 1 46%; }
  .exp-f--btns { width: 100%; }
  .exp-f--btns .btn { flex: 1; }
}
.xp-table-wrap .num{font-variant-numeric:tabular-nums}
.xp-muted{color:var(--ink-faint)}
.xp-pctbar{position:relative;display:inline-flex;align-items:center;width:74px;height:16px;overflow:hidden;
  border:1px solid var(--line);border-radius:999px;background:var(--surface-3);font-family:var(--f-mono);
  font-size:10px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.xp-pctbar-fill{position:absolute;inset:0 auto 0 0;background:var(--sonar);opacity:.5}
.xp-pctbar b{position:relative;z-index:1;margin:0 auto;padding:0 4px}
.xp-footnote{font-size:11.5px;line-height:1.45;color:var(--ink-faint)}
.xp-price-timeline-body{display:flex;flex-direction:column;gap:10px}
.xp-pricing-headline{font-family:var(--f-mono);font-size:11.5px;color:var(--ink-dim);line-height:1.35}
.xp-pricing-headline b{color:var(--ink)}
.xp-price-chart-wrap{position:relative;border:1px solid var(--line-soft);border-radius:var(--radius-sm);
  background:linear-gradient(180deg,var(--surface),var(--surface-2));padding:8px 8px 6px}
.xp-price-svg{display:block;width:100%;height:150px;overflow:visible}
.xp-price-axis{font-family:var(--f-mono);font-size:10px;fill:var(--ink-faint)}
.xp-price-band{fill:var(--sonar-dim)}
.xp-price-line{fill:none;stroke:var(--sonar-deep);stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
.xp-price-dot{fill:var(--surface);stroke:var(--ink);stroke-width:1.5}
.xp-price-caret{font-family:var(--f-mono);font-size:11px;font-weight:800;text-anchor:middle}
.xp-price-caret.is-up,.xp-price-change.is-up{color:var(--coral);fill:var(--coral)}
.xp-price-caret.is-down,.xp-price-change.is-down{color:var(--sonar-deep);fill:var(--sonar-deep)}
.xp-price-label{font-family:var(--f-mono);font-size:10px;fill:var(--ink);paint-order:stroke;stroke:var(--surface);stroke-width:4;stroke-linejoin:round}
.xp-price-tip{position:absolute;z-index:4;max-width:260px;pointer-events:none;border:1px solid var(--line);
  border-radius:var(--radius-sm);background:var(--surface);box-shadow:var(--shadow);padding:7px 9px;
  font-family:var(--f-mono);font-size:10.5px;line-height:1.45;color:var(--ink)}
.xp-price-tip[hidden]{display:none}
.xp-price-changes{display:flex;flex-direction:column;gap:6px;margin-top:2px}
.xp-price-change-row{display:flex;align-items:center;justify-content:space-between;gap:8px;
  border:1px solid var(--line-soft);border-radius:var(--radius-sm);background:var(--surface);padding:6px 8px;
  font-family:var(--f-mono);font-size:10.5px;color:var(--ink-dim)}
.xp-price-change-row b{font-weight:700;color:var(--ink)}
.xp-hist{min-height:156px;display:flex;align-items:flex-end;gap:4px;border-bottom:1px solid var(--line);padding:12px 4px 6px}
.xp-hcol{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:4px}
.xp-hval{font-family:var(--f-mono);font-size:9px;color:var(--ink-dim);line-height:1}
.xp-hbar{width:100%;max-width:34px;min-height:2px;border-radius:2px 2px 0 0;background:var(--sonar-dim);border-top:2px solid var(--sonar)}
.xp-hlbl{font-family:var(--f-mono);font-size:9px;color:var(--ink-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.xp-split{display:grid;grid-template-columns:1fr;gap:14px}
.xp-feed{display:flex;flex-direction:column;gap:7px;max-height:350px;overflow:auto;padding-right:2px}
.xp-feed-row{display:grid;grid-template-columns:72px minmax(0,1fr) auto;gap:10px;align-items:center;
  border:1px solid var(--line-soft);border-left:3px solid var(--line);border-radius:var(--radius-sm);
  background:var(--surface);padding:8px 10px}
.xp-feed-row.is-add{border-left-color:var(--sonar)}
.xp-feed-row.is-remove{border-left-color:var(--coral)}
.xp-feed-time{font-family:var(--f-mono);font-size:10.5px;color:var(--ink-faint)}
.xp-feed-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink)}
.xp-feed-meta{font-family:var(--f-mono);font-size:11px;color:var(--ink-dim);white-space:nowrap}
.xp-empty{padding:24px;text-align:center;color:var(--ink-faint);font-size:13px}

/* ── restocks: dense watchlist + event page ── */
.rk-tools{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.rk-search{font-family:var(--f-mono);font-size:12px;padding:6px 10px;border:1px solid var(--line);
  border-radius:var(--radius-sm);background:var(--surface);color:var(--ink);min-width:200px}
.rk-list{display:flex;flex-direction:column}
.rk-row{display:flex;align-items:center;gap:12px;padding:10px 14px;border-bottom:1px solid var(--line-soft);
  color:var(--ink);text-decoration:none;transition:background .12s}
.rk-row:last-child{border-bottom:none}
.rk-row:hover{background:var(--surface-2)}
.rk-heat{width:9px;height:9px;border-radius:99px;flex:none;background:var(--ink-ghost)}
.rk-heat.heat-hot{background:var(--coral);box-shadow:0 0 0 3px var(--coral-glow)}
.rk-heat.heat-warm{background:var(--amber);box-shadow:0 0 0 3px var(--amber-glow)}
.rk-heat.heat-cold{background:var(--tide)}
.rk-main{min-width:0;flex:1 1 auto;display:flex;flex-direction:column;gap:1px}
.rk-name{font-family:var(--f-display);font-weight:700;font-size:13.5px;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.rk-sub{font-size:11px;color:var(--ink-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rk-spark{width:120px;height:28px;flex:none}
.rk-spark polyline{fill:none;stroke:var(--sonar);stroke-width:1.5}
.rk-spark .area{fill:var(--sonar-dim);stroke:none}
.rk-nums{display:flex;align-items:center;gap:14px;flex:none;font-size:11.5px;color:var(--ink-dim);
  font-variant-numeric:tabular-nums}
.rk-num b{color:var(--ink);font-weight:600}
.rk-price{min-width:86px;text-align:right}
.rk-ago{min-width:52px;text-align:right;color:var(--ink-faint)}
@media (max-width:700px){
  .rk-spark{display:none}
  .rk-row{flex-wrap:wrap;row-gap:4px;padding:10px 12px}
  .rk-main{flex-basis:calc(100% - 60px)}
  .rk-nums{width:100%;justify-content:flex-start;padding-left:21px;gap:12px}
  .rk-price,.rk-ago{min-width:0;text-align:left}
}
.rke-back{color:var(--ink-faint);text-decoration:none;font-size:11px}
.rke-back:hover{color:var(--ink)}
/* Not sticky: the fleet bar is sticky at top:0/z-20 with a VARIABLE (wrapping) height, so any
   fixed sticky offset here either hides the tabs under it or gaps — plain flow scrolls clean. */
.rke-tabs{display:flex;gap:6px;margin:0 0 14px}
.rke-tab{font-family:var(--f-mono);font-size:11.5px;font-weight:600;color:var(--ink-dim);
  border:1px solid var(--line);border-radius:999px;padding:6px 16px;background:var(--surface);cursor:pointer}
.rke-tab.on{background:var(--sonar-dim);border-color:var(--sonar);color:var(--sonar-deep)}
.rke-pane{display:none}
.rke-pane.on{display:block}
.rke-map{min-height:200px}
.rke-feed-tools{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.rke-feed-drop{font-size:10.5px;color:var(--ink-faint);margin:8px 0 2px;padding-left:2px}
#rkeFeedMore{margin-top:8px}
.price-chips{display:inline-flex;gap:6px;flex-wrap:wrap}
.price-chip{font-family:var(--f-mono);font-size:11px;font-weight:600;color:var(--ink-dim);
  border:1px solid var(--line);border-radius:999px;padding:2px 9px;background:var(--surface);cursor:pointer}
.price-chip.on{background:var(--sonar-dim);border-color:var(--sonar);color:var(--sonar-deep)}

/* ============================ Queue — queue-gated carting ============================
   This tab answers one question before it answers anything else: is this queue alive, and how close
   am I to the front? So it reads top-to-bottom as COMMAND -> THE LINE -> WHAT NEEDS ME -> THE
   ROSTER, and the hero is a plot of the line itself rather than a row of summary tiles.

   Colour is load-bearing and follows the console's existing semantics exactly — green = through,
   blue = moving, amber = wants a human, coral = dead. Nothing here is decorative; if a colour
   appears, it is carrying a status.
   ==================================================================================== */
.vs-tag.queue-tag { cursor: pointer; padding: 2px 5px; }
.vs-tag.queue-tag .ico { width: 12px; height: 12px; }

/* ---- SHARED with the Cards tab (checkout-log chips) — not queue-only, don't fold these in ----
   nowrap: these are single tokens ("2✓ 3✗", "U103 8") and breaking one across two lines reads as
   two separate chips. */
.q-chip { font-family: var(--f-mono); font-size: 10px; padding: 2px 7px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink-dim);
  white-space: nowrap; }
.q-chip--on { background: var(--sonar-dim); border-color: var(--sonar); color: var(--sonar-deep); font-weight: 700; }
.q-chip--warn { background: rgba(176, 122, 16, .07); border-color: var(--amber-glow); color: var(--amber); font-weight: 700; }
.q-activity { display: flex; flex-wrap: wrap; gap: 5px; margin: 4px 0 8px; }
.btn--xs { font-size: 10.5px; padding: 2px 8px; }

/* ---- layout ----
   minmax(0,1fr) on the right column is load-bearing: a grid item defaults to min-width:auto, so the
   roster table's own min-content would become the floor for the track and push the panel wider than
   the page instead of scrolling inside itself. */
.q-layout { display: grid; grid-template-columns: minmax(240px, 300px) minmax(0, 1fr); gap: 16px; align-items: start; }
.q-detail { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
@media (max-width: 1000px) { .q-layout { grid-template-columns: 1fr; } }
/* The `hidden` attribute is a UA rule, so ANY class here that sets `display` silently beats it and
   the element stays on screen — which is how a stopped event kept showing its Stop button. Same
   per-class opt-back-in the rest of this sheet uses (.map-tip[hidden], .rp-pill[hidden], …). */
.q-detail[hidden], .q-health[hidden], .q-more[hidden], .q-cmd__acts .btn[hidden] { display: none; }

/* ---- engines: a set-and-forget config, so it lives in a popover instead of owning the top of the
   page the way it used to ---- */
.q-engines { position: relative; }
.q-engines > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--f-mono); font-size: 11px; padding: 7px 13px; border: 1px solid var(--line);
  border-radius: 999px; background: var(--surface); color: var(--ink-dim); white-space: nowrap; }
.q-engines > summary::-webkit-details-marker { display: none; }
.q-engines > summary:hover { border-color: var(--line-strong); color: var(--ink); }
.q-engines > summary:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--accent-dim); }
.q-engines[open] > summary { border-color: var(--accent-glow); background: var(--accent-dim); color: var(--accent-deep); }
.q-engines .ico { width: 14px; height: 14px; }
/* width is viewport-clamped, not fixed: below 880px .page-head__r becomes a 1fr 1fr grid, so this
   summary is only half the header wide. A fixed 296px panel right-aligned to that half hangs off
   the left of a small phone, and the shell's overflow clipping makes it unreachable. */
.q-engines__pop { position: absolute; right: 0; top: calc(100% + 8px); z-index: 40;
  width: min(296px, calc(100vw - 36px));
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 13px; }
@media (max-width: 880px) {
  .q-engines { grid-column: 1 / -1; }                  /* full width, so the popup anchors sanely */
  .q-engines > summary { width: 100%; justify-content: center; }
}
.q-engines__pop p { margin: 0 0 10px; font-size: 11.5px; color: var(--ink-faint); }
.q-engine { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 12.5px; padding: 5px 2px; }
.q-engine-name { font-weight: 600; flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.q-engines__foot { display: flex; align-items: center; gap: 9px; margin-top: 11px; padding-top: 11px;
  border-top: 1px solid var(--line-soft); }

/* The page header owns BOTH popovers (Queue settings, Engines), and both hang down over the panels
   below. `.reveal-in` leaves a transform on the header — an identity matrix, but a transform all the
   same — and a transform CREATES A STACKING CONTEXT. That traps every descendant's z-index inside
   the header, so the popovers' `z-index: 40` competed only with each other and the whole header then
   painted underneath `.q-layout`, which simply comes later in the document. The popovers rendered as
   see-through: their own background drew, and the plot and roster drew straight over the top.
   Raising the header itself is the fix — it changes no layout, only paint order, and the header's
   own box does not overlap anything when the popovers are shut. */
.q-head { position: relative; z-index: 30; }

/* ---- queue settings popover ----
   Same shell as the Engines popover, but wider and scrollable: it carries every [queue] key in
   settings.toml with its help text, and that is a form rather than a checklist. */
.q-settings__pop { width: min(560px, calc(100vw - 36px)); max-height: min(72vh, 640px);
  overflow: hidden auto; }
.q-set__grp { border-top: 1px solid var(--line-soft); }
.q-set__grp > summary { list-style: none; cursor: pointer; padding: 9px 2px; font-size: 11px;
  font-family: var(--f-mono); letter-spacing: .8px; text-transform: uppercase; color: var(--ink-faint); }
.q-set__grp > summary::-webkit-details-marker { display: none; }
.q-set__grp > summary:hover { color: var(--ink); }
.q-set__grp > summary b { color: var(--ink-ghost); font-weight: 500; }
.q-set__row { padding: 8px 2px 10px; border-top: 1px solid var(--line-soft); }
.q-set__k { display: block; font-family: var(--f-mono); font-size: 11.5px; font-weight: 600;
  color: var(--ink); margin-bottom: 5px; overflow-wrap: anywhere; }
.q-set__v input[type="text"], .q-set__v input[type="number"] { width: 100%; box-sizing: border-box;
  font-size: 12px; padding: 5px 8px; border: 1px solid var(--line-strong); border-radius: 5px;
  background: var(--surface); color: var(--ink); }
.q-set__bool { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; font-size: 12px;
  font-family: var(--f-mono); color: var(--ink-dim); }
/* The help text is long-form prose from settings.toml, so it wraps — it is the only thing in this
   panel that may. Clamped so one very talkative key cannot push the Save button off the popover. */
.q-set__h { margin: 6px 0 0; font-size: 11px; line-height: 1.45; color: var(--ink-faint);
  white-space: normal; overflow-wrap: anywhere; max-height: 5.8em; overflow-y: auto; }

/* ---- event rail ---- */
/* overflow-x is pinned to hidden: setting only overflow-y makes the other axis compute to `auto`,
   which gave the rail a stray horizontal scrollbar. The cards ellipsis instead. */
.q-evs { display: flex; flex-direction: column; gap: 6px; padding: 10px;
  max-height: calc(100vh - 230px); overflow: hidden auto; }
.q-ev { display: block; width: 100%; text-align: left; padding: 10px 11px; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); }
.q-ev:hover { border-color: var(--line-strong); background: var(--surface-2); }
.q-ev:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--accent-dim); }
.q-ev.is-sel { border-color: var(--accent); background: var(--accent-dim); box-shadow: inset 2px 0 0 var(--accent); }
.q-ev__top { display: flex; align-items: center; gap: 8px; min-width: 0; }
.q-ev__dot { width: 7px; height: 7px; border-radius: 99px; background: var(--ink-ghost); flex: none; }
/* An armed event is the only thing on this page that breathes. One live signal, so it means something. */
.q-ev.is-armed .q-ev__dot { background: var(--sonar); animation: qpulse 2.6s ease-in-out infinite; }
@keyframes qpulse { 0%, 100% { box-shadow: 0 0 0 0 var(--sonar-glow); } 55% { box-shadow: 0 0 0 5px transparent; } }
.q-ev__name { font-weight: 600; font-size: 13px; flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* display:block is load-bearing, not tidiness — these are <span>s inside a <button>, and
   text-overflow:ellipsis does nothing on an inline box, so the venue line ran past the card edge. */
.q-ev__meta { display: block; font-size: 10.5px; color: var(--ink-faint); margin-top: 3px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The whole fleet's state as one 4px rule — readable at rail width, where six chips are not. */
.q-ev__bar { display: flex; height: 4px; border-radius: 99px; overflow: hidden; background: var(--surface-3); margin-top: 9px; }
.q-ev__bar i { display: block; height: 100%; }
.q-ev__bar i.t { background: var(--sonar); }
.q-ev__bar i.q { background: var(--accent); }
.q-ev__bar i.f { background: var(--coral); }
.q-ev__nums { display: flex; gap: 9px; margin-top: 6px; font-family: var(--f-mono); font-size: 10px;
  color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.q-ev__nums b { font-weight: 600; color: var(--ink-dim); }
.q-ev__nums .t b { color: var(--sonar-deep); }
.q-ev__flags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 7px; }

/* ---- command bar ---- */
.q-cmd { display: flex; align-items: flex-start; gap: 14px; flex-wrap: wrap; padding: 14px 17px; }
.q-cmd__l { flex: 1 1 300px; min-width: 0; }
.q-cmd h2 { margin: 0; font-size: 18px; letter-spacing: -.2px; }
.q-cmd__meta { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-top: 5px;
  font-size: 12px; color: var(--ink-faint); }
.q-cmd__acts { display: flex; gap: 8px; flex-wrap: wrap; }

/* ---- THE LINE: the signature instrument ----
   x is place in line, front on the LEFT. The bars are a density histogram of where the fleet is
   standing right now; the caps on either side hold the accounts that are OFF the scale — through it
   on the left, no number yet on the right. */
.q-line { padding: 15px 17px 0; }
.q-line__head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 11px; }
.q-line__title { font-family: var(--f-mono); font-size: 9px; letter-spacing: 1.6px;
  text-transform: uppercase; color: var(--ink-faint); }
.q-line__note { font-size: 11.5px; color: var(--ink-faint); }
.q-line__rig { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 9px; align-items: stretch; }
.q-cap { display: flex; flex-direction: column; align-items: center; justify-content: center; min-width: 64px;
  padding: 8px 11px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface-2); }
.q-cap b { font-family: var(--f-mono); font-size: 18px; font-weight: 600; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--ink-dim); }
.q-cap span { font-family: var(--f-mono); font-size: 8px; letter-spacing: 1.1px; text-transform: uppercase;
  color: var(--ink-faint); margin-top: 6px; text-align: center; }
.q-cap--through { border-color: var(--sonar-glow); background: var(--sonar-dim); }
.q-cap--through b { color: var(--sonar-deep); }
.q-cap.is-zero { opacity: .5; }
/* The floor tint is brightest at the front of the line — the left edge is the good end. */
.q-plot { position: relative; height: 92px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--accent-dim), rgba(46, 95, 215, .015) 55%, transparent);
  overflow: hidden; }
/* One bar per account, sorted front-to-back. The gradient runs with the line, so an account near
   the front is drawn in the accent's full strength and the stragglers fade back. */
.q-plot__bars { position: absolute; left: 0; right: 0; top: 0; bottom: 17px;
  display: flex; align-items: flex-end; justify-content: flex-start; gap: 1px; padding: 9px 8px 0; }
/* max-width matters at small N: without it, six accounts render as six slabs filling the panel,
   which reads as a wall rather than a short line. Capped, the bars stay ticks and the strip's
   LENGTH becomes a second honest reading — how many accounts are standing in the line at all. */
.q-plot__bars i { flex: 1 1 0; min-width: 0; max-width: 9px; background: var(--accent);
  border-radius: 1.5px 1.5px 0 0; opacity: .78; }
.q-plot__axis { position: absolute; left: 0; right: 0; bottom: 0; height: 17px; display: flex;
  align-items: center; justify-content: space-between; gap: 8px; padding: 0 8px;
  border-top: 1px solid var(--line-soft); background: var(--surface);
  font-family: var(--f-mono); font-size: 8.5px; letter-spacing: .6px; color: var(--ink-faint);
  font-variant-numeric: tabular-nums; }
.q-plot__axis span { white-space: nowrap; }
/* On a phone the three-across rig squeezed the plot to ~130px — narrower than its own axis labels,
   so the instrument vanished and only wrapped text remained. Give the plot the full width and sit
   the two caps under it. */
@media (max-width: 620px) {
  .q-line__rig { grid-template-columns: 1fr 1fr; }
  .q-line__rig > .q-plot { grid-column: 1 / -1; order: -1; }
  .q-cap { min-width: 0; }
}
.q-plot__empty { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 12px; color: var(--ink-faint); padding: 0 14px; text-align: center; }

/* Figures under the plot: hairline-separated by a 1px grid gap over a soft line colour. */
.q-figs { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 1px;
  background: var(--line-soft); margin-top: 15px; border-top: 1px solid var(--line-soft); }
.q-fig { background: var(--surface); padding: 11px 17px 13px; }
.q-fig__k { font-family: var(--f-mono); font-size: 8.5px; letter-spacing: 1.3px; text-transform: uppercase;
  color: var(--ink-faint); }
.q-fig__v { font-family: var(--f-mono); font-size: 19px; font-weight: 600; letter-spacing: -.4px;
  line-height: 1.1; margin-top: 6px; font-variant-numeric: tabular-nums; }
.q-fig__v .u { font-size: 11px; color: var(--ink-faint); font-weight: 400; margin-left: 3px; letter-spacing: 0; }
.q-fig__s { font-size: 11px; color: var(--ink-dim); margin-top: 4px; }
.q-fig--good .q-fig__v { color: var(--sonar-deep); }
.q-fig--warn .q-fig__v { color: var(--amber); }
.q-fig--idle .q-fig__v { color: var(--ink-faint); }

/* ---- health band: one sentence about whether anything needs a human ---- */
.q-health { display: flex; align-items: center; gap: 10px; padding: 10px 15px; font-size: 13px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); }
.q-health .ico { width: 16px; height: 16px; flex: none; }
.q-health__txt { flex: 1 1 auto; min-width: 0; }
.q-health--ok { border-color: var(--sonar-glow); background: var(--sonar-dim); color: var(--sonar-deep); }
.q-health--warn { border-color: var(--amber-glow); background: rgba(176, 122, 16, .06); color: var(--amber); }
.q-health--bad { border-color: var(--coral-glow); background: rgba(210, 59, 76, .05); color: var(--coral); }

/* ---- setup: frozen while the event runs, so it collapses out of the way ---- */
.q-setup > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 10px;
  padding: 13px 17px; font-weight: 600; font-size: 13.5px; }
.q-setup > summary::-webkit-details-marker { display: none; }
.q-setup > summary:hover { background: var(--surface-2); }
.q-setup > summary:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent-glow); }
.q-setup__chev { margin-left: auto; color: var(--ink-faint); transition: transform .18s ease; }
.q-setup[open] .q-setup__chev { transform: rotate(90deg); }
.q-setup__sum { font-family: var(--f-mono); font-size: 11px; font-weight: 400; color: var(--ink-faint); }
.q-setup__body { padding: 0 17px 16px; border-top: 1px solid var(--line-soft); }
.q-profiles { display: flex; flex-direction: column; gap: 11px; padding-top: 14px; }
.q-profile-list { display: flex; flex-wrap: wrap; gap: 9px; }
.q-profile { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; padding: 4px 9px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--surface); cursor: pointer; }
.q-profile:hover { border-color: var(--line-strong); }
/* input.: the base rule is `input[type=number]{width:100%}` (0,1,1), so a bare class never wins
   and the race box stretched across the whole panel. */
input.q-race-input { width: 76px; margin-left: 6px; }
.q-locked { opacity: .5; }
.q-locked .q-profile { cursor: not-allowed; }

/* ---- roster ---- */
.q-tools { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; padding: 11px 14px;
  border-bottom: 1px solid var(--line-soft); }
.q-search { flex: 1 1 190px; min-width: 140px; max-width: 300px; }
.q-filters { display: flex; gap: 4px; flex-wrap: wrap; }
.q-filter { font-family: var(--f-mono); font-size: 10.5px; padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink-dim); cursor: pointer;
  white-space: nowrap; font-variant-numeric: tabular-nums; }
.q-filter:hover { border-color: var(--line-strong); color: var(--ink); }
.q-filter:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--accent-dim); }
.q-filter.is-on { background: var(--accent-dim); border-color: var(--accent-glow); color: var(--accent-deep); font-weight: 700; }
/* A filter matching nothing is dimmed, never hidden — "0 failed" is an answer, and a bar whose
   chips come and go between polls can't be learned. (Same rule as the Cards filter bar.) */
.q-filter.is-zero { opacity: .45; }
.q-filter.is-on.is-zero { opacity: 1; }
.q-tablewrap { overflow: auto; max-height: 64vh; }
.q-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12.5px; }
/* Sticky header: with hundreds of accounts you scroll far enough to forget which column is which. */
.q-table thead th { position: sticky; top: 0; z-index: 2; background: var(--surface); padding: 0;
  text-align: left; white-space: nowrap; border-bottom: 1px solid var(--line);
  font-family: var(--f-mono); font-size: 8.5px; font-weight: 500; letter-spacing: 1.3px;
  text-transform: uppercase; color: var(--ink-faint); }
/* The sort control is a real <button> inside the <th> so it is focusable and announced as a control;
   aria-sort stays on the <th> where assistive tech expects it. */
.q-table th button { all: unset; box-sizing: border-box; display: flex; align-items: center; gap: 5px;
  width: 100%; padding: 10px 10px; cursor: pointer; font: inherit; color: inherit; }
.q-table th button:hover { color: var(--ink); background: var(--surface-2); }
.q-table th button:focus-visible { box-shadow: inset 0 0 0 2px var(--accent-glow); color: var(--ink); }
.q-table th.num button { justify-content: flex-end; }
/* The arrow always occupies its slot, so header text never shifts as you click between columns. */
.q-arw { font-size: 8px; opacity: 0; }
.q-table th.is-sorted { color: var(--accent-deep); }
.q-table th.is-sorted .q-arw { opacity: 1; }
/* Every cell is ONE line. A wrapped profile name ("aged-2023" breaking after the hyphen) makes that
   row twice as tall as its neighbours, and a table of three hundred accounts at two heights cannot
   be scanned. Long values ellipsis inside their own cell instead. */
/* 10px, not 12: the roster gained two columns (Last change, and the Token action) and eight columns
   of 12px padding put the table past its wrapper. The wrapper scrolls, so nothing broke — but the
   actions are the LAST columns, so what scrolled out of sight was Release. */
.q-table td { padding: 8px 10px; border-bottom: 1px solid var(--line-soft); vertical-align: middle;
  white-space: nowrap; }
.q-table td.prof { max-width: 130px; overflow: hidden; text-overflow: ellipsis; }
/* The status line is the only unbounded string in the row (it carries Ticketmaster's own prose), so
   it is the column that decides whether the roster fits. Capped hard and ellipsised rather than
   allowed to set the table's width: eight columns of nowrap data plus a scrollbar is a worse read
   than a truncated sentence whose full text is one hover away in title=. */
.q-table td.st { max-width: 250px; width: 250px; }
.q-table tbody tr:hover td { background: var(--surface-2); }
.q-table td.num, .q-table th.num { text-align: right; }
.q-num { font-family: var(--f-mono); font-size: 11.5px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.q-num--ghost { color: var(--ink-ghost); }
.q-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; max-width: 260px; }
.q-who b { font-family: var(--f-mono); font-size: 11.5px; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.q-who span { font-size: 10px; color: var(--ink-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Status: a dot carries the state, the words carry the detail. One line, always. */
.q-st { display: flex; align-items: center; gap: 7px; min-width: 0; }
.q-st__dot { width: 7px; height: 7px; border-radius: 99px; flex: none; background: var(--ink-ghost); }
.q-st__txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.q-st--through .q-st__dot { background: var(--sonar); }
.q-st--moving .q-st__dot { background: var(--accent); }
.q-st--attention .q-st__dot { background: var(--amber); }
.q-st--dead .q-st__dot { background: var(--coral); }
.q-st--attention .q-st__txt { color: var(--amber); }
.q-st--dead .q-st__txt { color: var(--coral); }
/* Per-row travel: how far this account has come from the number it was given, which is the only
   per-row way to see MOVEMENT rather than a position that could have been written an hour ago. */
.q-rail { display: flex; align-items: center; gap: 8px; min-width: 132px; }
.q-rail__t { position: relative; flex: 1 1 auto; height: 5px; border-radius: 99px;
  background: var(--surface-3); overflow: hidden; }
.q-rail__f { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 99px; background: var(--accent); }
.q-rail--done .q-rail__f { background: var(--sonar); }
.q-rail__n { font-family: var(--f-mono); font-size: 11.5px; font-variant-numeric: tabular-nums;
  white-space: nowrap; min-width: 62px; text-align: right; }
.q-more { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 12px;
  border-top: 1px solid var(--line-soft); font-size: 12px; color: var(--ink-faint); }
/* Actions column: the per-row Token / Release controls, PINNED to the right edge.
   The roster is eight columns wide and the wrapper scrolls horizontally when it has to — which is
   correct for the data, and wrong for the buttons: the actions are the last columns, so on a narrow
   panel (or a row that carries both Token and Release) the thing that scrolled out of reach was
   Release, the only control anyone presses. Sticky keeps them on screen while the numbers slide
   underneath. The background is opaque for the same reason, and has to track the row hover or the
   pinned cell stays pale over a highlighted row. */
/* Sticky is a safety net for the narrowest cases, not the normal state — the column steps above keep
   the table inside its wrapper at every ordinary width. No edge shadow for that reason: it would
   draw a permanent seam down a table that is not scrolling. */
.q-table td.q-acts { position: sticky; right: 0; z-index: 1; background: var(--surface);
  padding: 6px 10px 6px 6px; white-space: nowrap; text-align: right; }
.q-table tbody tr:hover td.q-acts { background: var(--surface-2); }
.q-table thead th:last-child { position: sticky; right: 0; z-index: 3; background: var(--surface); }
.q-acts .btn { padding-left: 8px; padding-right: 8px; }
.q-acts .btn + .btn { margin-left: 4px; }
/* The token control is an icon: it appears on EVERY row, and a labelled button there cost more
   width than the column had. The name lives in title + aria-label, so it is still announced. */
.q-iconbtn { display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 24px; padding: 0; }
.q-iconbtn .ico { width: 13px; height: 13px; }

/* ---- the roster SHEDS COLUMNS rather than growing a horizontal scrollbar ----
   Eight columns of nowrap data only fit on a very wide window, and a sideways scrollbar under a
   sticky header is a genuinely bad way to read a table: half the row is always somewhere else, and
   the operator has to scroll back and forth to pair an account with its position.

   So the columns are dropped in order of least use, and each one is still in the payload — widen the
   window and it returns, and its sort header comes back with it.
     ETA         Ticketmaster's own guess, and the travel rail beside it already shows the position.
     Started at  a historical number; interesting once, not on every glance.
     Profile     nearly always the same value down the whole column, and it is searchable.
   Nothing that says whether an account is WORKING is ever dropped. */
@media (max-width: 1500px) {
  .q-table thead th:nth-child(6), .q-table tbody td:nth-child(6) { display: none; }   /* ETA */
}
@media (max-width: 1420px) {
  .q-table thead th:nth-child(4), .q-table tbody td:nth-child(4) { display: none; }   /* Started at */
}
@media (max-width: 1330px) {
  .q-table thead th:nth-child(2), .q-table tbody td:nth-child(2) { display: none; }   /* Profile */
  .q-table td.st { max-width: 200px; width: 200px; }
  .q-who { max-width: 165px; }
}
/* min-width as well as max-, and it is load-bearing: the layout already collapses to ONE column at
   1000px, and that rule lives earlier in this sheet. A bare `max-width: 1200px` here therefore wins
   on a phone too and re-imposes a 200px event rail on a 390px screen — which left the roster 86px
   wide. Any rule that narrows this grid has to stop before the single-column breakpoint. */
@media (min-width: 1001px) and (max-width: 1200px) {
  /* Give the table the width back from the event rail before touching any more columns. */
  .q-layout { grid-template-columns: minmax(200px, 236px) minmax(0, 1fr); }
  .q-rail { min-width: 96px; gap: 6px; }
  .q-rail__n { min-width: 52px; }
  .q-who { max-width: 150px; }
}
/* Phone. Down to three things — who, where they are, and the controls. The status PROSE goes (it is
   the longest string in the row and the dot beside the account already carries the state), and the
   dot is moved onto the account cell so nothing about the row's health is actually lost. */
@media (max-width: 760px) {
  .q-table thead th:nth-child(3), .q-table tbody td:nth-child(3),
  .q-table thead th:nth-child(7), .q-table tbody td:nth-child(7) { display: none; }
  .q-table td, .q-table th button { padding-left: 8px; padding-right: 8px; }
  .q-rail { min-width: 66px; gap: 5px; }
  .q-rail__n { min-width: 42px; }
  /* A PIXEL cap, not 100%: inside an auto-layout table a percentage resolves against a cell that is
     itself sized by its content, so the email would keep setting the column width and never
     ellipsise. This is the one place the account address is allowed to be cut off. */
  .q-who { max-width: 108px; }
  .q-who b { font-size: 11px; }
  .q-table td.q-acts { padding: 4px 6px 4px 4px; }
  .q-acts .btn { font-size: 10px; }
}

/* ---- page freshness: how long since the browser last heard from the hub ----
   Its own signal, separate from every "hub write" figure. Quiet by default; it is only interesting
   once it stops being small. */
.q-fresh { display: block; margin-top: 5px; font-family: var(--f-mono); font-size: 10.5px;
  color: var(--ink-ghost); }
.q-fresh:empty { display: none; }
.q-fresh.is-stale { color: var(--amber); font-weight: 700; }

/* ---- Accounts | Log segmented control ---- */
.q-views { display: inline-flex; gap: 2px; padding: 2px; border: 1px solid var(--line);
  border-radius: 999px; background: var(--surface-2); }
.q-view { display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 12px; font-weight: 600; padding: 5px 13px; border-radius: 999px;
  border: 1px solid transparent; background: transparent; color: var(--ink-dim); }
.q-view .ico { width: 13px; height: 13px; }
.q-view:hover { color: var(--ink); }
.q-view:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--accent-dim); }
.q-view.is-on { background: var(--surface); border-color: var(--line-strong); color: var(--ink); }

/* `[hidden]` is a UA rule and loses to ANY class here that sets `display`, which is how a hidden
   panel stays on screen. Same per-class opt-back-in used throughout this sheet. */
#q-accounts-view[hidden], #q-log-view[hidden], .q-tok[hidden], .q-filters[hidden] { display: none; }

/* ---- the log: what the queue did while nobody was watching ---- */
.q-log { list-style: none; margin: 0; padding: 0; max-height: 64vh; overflow: auto; }
.q-log__row { display: grid; grid-template-columns: 8px 52px minmax(0, 170px) minmax(0, 1fr);
  align-items: baseline; gap: 10px; padding: 8px 14px; border-bottom: 1px solid var(--line-soft);
  font-size: 12.5px; }
.q-log__row:hover { background: var(--surface-2); }
.q-log__dot { width: 6px; height: 6px; border-radius: 99px; background: var(--ink-ghost);
  align-self: center; }
.q-log__row--warn .q-log__dot { background: var(--amber); }
.q-log__row--error .q-log__dot { background: var(--coral); }
.q-log__t { font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-faint);
  text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.q-log__who { font-family: var(--f-mono); font-size: 11px; color: var(--ink-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.q-log__who i { font-style: normal; color: var(--ink-ghost); }
.q-log__msg { color: var(--ink); min-width: 0; }
.q-log__row--error .q-log__msg { color: var(--coral); }
.q-log__empty { padding: 34px 14px; text-align: center; color: var(--ink-faint); font-size: 12.5px; }
/* Below ~640px the four-column grid cannot hold a sentence, so the message drops to its own row
   under the time and account rather than being squeezed to two words a line. */
@media (max-width: 640px) {
  .q-log__row { grid-template-columns: 8px 52px minmax(0, 1fr); }
  .q-log__msg { grid-column: 2 / -1; }
}

/* ---- token inspection: one account, on demand ---- */
.q-tok { padding: 13px 14px; border-bottom: 1px solid var(--line-soft); background: var(--surface-2); }
.q-tok__head { display: flex; align-items: center; gap: 9px; margin-bottom: 8px; }
.q-tok__head b { font-family: var(--f-mono); font-size: 12px; flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; }
.q-tok__state { margin: 0 0 10px; font-size: 12px; }
.q-tok__state--good { color: var(--sonar-deep); }
.q-tok__state--warn { color: var(--amber); }
.q-tok__state--bad { color: var(--coral); }
.q-tok__state--idle { color: var(--ink-faint); }
.q-tok__f { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.q-tok__k { font-family: var(--f-mono); font-size: 9.5px; letter-spacing: .6px; text-transform: uppercase;
  color: var(--ink-faint); flex: none; width: 118px; }
/* The value scrolls inside itself: a queueittoken is hundreds of characters and wrapping one across
   six lines pushes every other field off the screen. */
.q-tok__v { flex: 1 1 auto; min-width: 0; font-family: var(--f-mono); font-size: 11px;
  padding: 4px 8px; border: 1px solid var(--line); border-radius: 5px; background: var(--surface);
  color: var(--ink-dim); white-space: nowrap; overflow-x: auto; }
.q-tok__note { margin: 8px 0 0; font-size: 11.5px; color: var(--ink-faint); }
@media (max-width: 640px) {
  .q-tok__f { flex-wrap: wrap; }
  .q-tok__k { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .q-ev.is-armed .q-ev__dot { animation: none; box-shadow: 0 0 0 3px var(--sonar-dim); }
  .q-setup__chev { transition: none; }
}

/* ---- Orders: PO Account (also rendered per-row in Sales > Missing) ---------------------- */
.po-wrap { display: inline-flex; align-items: center; gap: 8px; }
.po-btn { white-space: nowrap; }
.po-cell { white-space: nowrap; }
.po-pill[hidden] { display: none; }
.po-pill .po-pill-txt:empty { display: none; }
.po-curl { width: 100%; box-sizing: border-box; font-family: var(--f-mono); font-size: 12px;
  resize: vertical; border: 1px solid var(--line-strong); border-radius: 6px; padding: 10px;
  background: var(--surface-2); color: var(--ink); word-break: break-all; }
.po-field-label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-faint); margin: 10px 0 4px; }
.po-log-meta { font-family: var(--f-mono); font-size: 12px; color: var(--ink-faint); margin-bottom: 12px; }
.po-step { margin-bottom: 18px; }
.po-step-h { font-weight: 600; font-size: 13px; margin-bottom: 6px; color: var(--ink); }
.po-sub { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-faint);
  margin: 8px 0 4px; }
.po-pre { background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: 6px;
  padding: 10px; overflow-x: auto; font-family: var(--f-mono); font-size: 11.5px;
  white-space: pre-wrap; word-break: break-word; max-height: 320px; overflow-y: auto; margin: 0; }
.po-note { color: var(--ink-faint); font-size: 12px; margin: 6px 0; }

/* =========================================================================================
   PROVISIONING PANEL — "Add a server" (top of Settings, moved off the Dashboard)
   ========================================================================================= */
.provision { margin-bottom: var(--gap); }
.provision__head { cursor: pointer; list-style: none; gap: 12px; align-items: center; }
.provision__head::-webkit-details-marker { display: none; }
.provision__icon {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 32px; height: 32px; border-radius: 8px;
  background: var(--accent-dim); color: var(--accent);
}
.provision__icon .ico { width: 17px; height: 17px; }
.provision__titles { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.provision__titles .sub { font-family: var(--f-body); font-size: 12.5px; color: var(--ink-dim); }
.provision__chev {
  flex: none; width: 16px; height: 16px; color: var(--ink-faint);
  transition: transform .18s ease;
}
.provision[open] .provision__chev { transform: rotate(90deg); }
.provision__head:hover .provision__chev { color: var(--ink); }

.cmd { margin-bottom: 14px; }
.cmd:last-of-type { margin-bottom: 0; }
.cmd__lbl {
  font-family: var(--f-mono); font-size: 9.5px; letter-spacing: 1.4px; text-transform: uppercase;
  color: var(--ink-faint); margin-bottom: 6px;
}
.cmd__row { display: flex; gap: 8px; align-items: stretch; }
.cmd__code {
  flex: 1; min-width: 0;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 10px 12px; font-size: 12px; line-height: 1.5; color: var(--ink);
  overflow-x: auto; white-space: pre;
}
.cmd__btn { flex: none; align-self: stretch; }

/* =========================================================================================
   MOBILE — EVENT ROWS AS REAL CARDS
   The generic table->card layer turns every <td> into a labelled full-width line, which for an
   event meant ~8 stacked lines and a pile of loose glyphs. These rules lay the same cells out on
   a small grid instead: identity on top, the three inputs as a labelled 3-up, the pill strip on
   its own line, and gates/actions on one final row. Every card gets the same shape.
   Selectors carry `table.data.ev-table` so they outrank the generic `table.data:not(.no-cards) td`.
   ========================================================================================= */
@media (max-width: 640px) {
  table.data.ev-table { display: block; table-layout: auto; }
  table.data.ev-table colgroup { display: none; }
  table.data.ev-table tbody { display: block; }

  /* The select checkbox is taken OUT of the grid and pinned to the card's top-left corner.
     Leaving it in the flow forced column 1 to the checkbox's ~20px, which then squashed the ACO
     toggle sharing that column. Out of flow, the three inputs get three genuinely equal columns. */
  /* Six columns, not three: the aco/qty/offer row needs three genuinely equal 2-column cells.
     Gates and actions each get their OWN full-width row. They used to share one row 50/50 (three
     gate tags | three action buttons, ~136px each), but the actions grew to four with the Explorer
     deep link — 184px against a 146px half. Every 6-column split is symmetric, so no reshuffle
     (2/4, shrinking the tags) buys the actions enough room; only a full-width row does, and that
     keeps the 40px touch targets instead of squeezing seven controls onto one line. */
  table.data.ev-table tbody tr {
    position: relative;
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    grid-template-areas:
      "main  main  main  main  main  main"
      "aco   aco   qty   qty   offer offer"
      "flt   flt   flt   flt   flt   flt"
      "gates gates gates gates gates gates"
      "act   act   act   act   act   act";
    gap: 11px 10px; align-items: center;
    padding: 13px 14px 13px 44px; margin-bottom: 10px;
  }
  table.data.ev-table td.ev-sel {
    position: absolute; left: 13px; top: 14px; width: auto; padding: 0;
  }
  table.data.ev-table tbody td {
    display: block; padding: 0; border-bottom: 0; min-height: 0;
    text-align: left; white-space: normal;
  }
  /* only the three inputs keep a caption; everything else is self-evident */
  table.data.ev-table tbody td::before { content: none; }
  table.data.ev-table tbody td.ev-aco::before,
  table.data.ev-table tbody td.ev-qty::before,
  table.data.ev-table tbody td.ev-offer::before {
    content: attr(data-label); display: block;
    font-family: var(--f-mono); font-size: 9px; letter-spacing: 1px; text-transform: uppercase;
    color: var(--ink-faint); font-weight: 500; margin-bottom: 5px; text-align: left;
  }

  table.data.ev-table td.ev-main  { grid-area: main; min-width: 0; }
  table.data.ev-table td.ev-aco   { grid-area: aco; }
  table.data.ev-table td.ev-qty   { grid-area: qty; }
  table.data.ev-table td.ev-offer { grid-area: offer; }
  table.data.ev-table td.ev-flt   { grid-area: flt; min-width: 0; }
  table.data.ev-table td.ev-gates { grid-area: gates; }
  table.data.ev-table td.ev-act   { grid-area: act; text-align: right; }

  /* the title may use two lines on a phone — but every card still clamps at the same 2 */
  .ev-main .t-primary {
    white-space: normal; overflow: hidden; text-overflow: ellipsis;
    display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical;
    font-size: 14px; line-height: 1.3;
  }
  .ev-meta { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2;
             -webkit-box-orient: vertical; font-size: 11.5px; margin-top: 3px; }

  .ev-aco .toggle { width: 100%; min-height: 38px; font-size: 12px; }
  .ev-qty .inp-mini, .ev-offer .inp-mini { width: 100%; font-size: 16px; padding: 9px 10px; }

  /* gates + actions: 40px targets, spaced apart, never a cluster of tiny glyphs */
  .ev-gates { display: flex; gap: 8px; }
  .ev-gates > * {
    margin-right: 0; min-width: 40px; min-height: 38px;
    justify-content: center; border-radius: 8px; font-size: 11px;
  }
  .ev-gates .ico { width: 16px; height: 16px; }
  .ev-act { display: flex; gap: 8px; justify-content: flex-end; }
  .ev-act > .icon-btn {
    margin-left: 0; min-width: 40px; min-height: 38px;
    align-items: center; justify-content: center; border-radius: 8px;
  }
  .ev-act .ico { width: 16px; height: 16px; }

  .filt-cell { gap: 6px; padding-bottom: 2px; }
  .filt-cell .pill, .filt-cell .vs-tag { min-height: 24px; }
}

/* =========================================================================================
   MOBILE — ENGINE ROWS
   Same problem, same cure: the status/name/meta/seen/actions flex row used to wrap into a
   ragged pile with 24px tap targets. Give each part its own line and the actions real buttons.
   ========================================================================================= */
@media (max-width: 880px) {
  .eng { padding: 14px; }
  .eng__top { flex-wrap: wrap; row-gap: 9px; column-gap: 8px; }
  .eng__name { max-width: none; flex: 1 1 auto; min-width: 0; font-size: 14.5px; }
  .eng__state { min-width: 0; }
  .eng__meta { flex: 1 1 100%; order: 5; font-size: 11px; }
  .eng__spacer { display: none; }
  .eng__seen { order: 6; font-size: 11px; }
  .eng__actions { order: 7; margin-left: auto; gap: 8px; }
  .eng__actions .icon-btn {
    min-width: 42px; min-height: 38px;
    align-items: center; justify-content: center; border-radius: 8px;
  }
  .eng__actions .ico { width: 16px; height: 16px; }

  /* select and pool strip each take their own full-width row rather than competing for one */
  .eng__bot { margin-top: 11px; row-gap: 9px; }
  .eng__bot select { flex: 1 1 100%; width: 100%; max-width: none; min-width: 0; font-size: 16px; padding: 10px 30px 10px 11px; }
  /* pools scroll as one strip rather than wrapping into a block that shoves the row taller */
  .pool-cell {
    flex-wrap: nowrap; overflow-x: auto; width: 100%;
    scrollbar-width: none; -ms-overflow-style: none; padding-bottom: 2px;
  }
  .pool-cell::-webkit-scrollbar { display: none; }
  .pool-cell > .pill { flex: none; }

  /* fleet-wide buttons: even 2-up grid instead of a ragged wrap */
  .eng-tools { width: 100%; justify-content: flex-start; }
  .eng-tools__btns { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; width: 100%; }
  .eng-tools__btns .btn { width: 100%; justify-content: center; }
}

/* =========================================================================================
   POLISH PASS — desktop
   ========================================================================================= */

/* Centre the content column. It was max-width'd but left-aligned, so every screen wider than
   1480px left a growing dead gutter on the right and the page looked off-centre. */
.content { margin-left: auto; margin-right: auto; }

/* The stat strip was pinned to 9 columns while the dashboard renders 11 cards, so two always
   orphaned onto a ragged second row. auto-fit fills whatever row it is on, at any count — and
   118px is small enough that all 11 land on one row on a normal desktop. */
.statline { grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); }

/* panels: slightly softer head, and a head that sits flush when the body is a table */
.panel__head h2 { line-height: 1.25; }
/* Edge gutters so a flush table's first/last columns line up with the panel head above them.
   TABLE MODE ONLY — below 640px these tables are cards, where a stray padding-left on the first
   cell shunts the absolutely-positioned select checkbox on top of the event title. */
@media (min-width: 641px) {
  .panel__body.flush > .table-wrap > table.data > thead > tr > th:first-child,
  .panel__body.flush > .table-wrap > table.data > tbody > tr > td:first-child { padding-left: 18px; }
  .panel__body.flush > .table-wrap > table.data > thead > tr > th:last-child,
  .panel__body.flush > .table-wrap > table.data > tbody > tr > td:last-child { padding-right: 18px; }
}

/* table rows: a real hover tint (was var(--surface) = white on a white panel, i.e. invisible) */
table.data tbody tr:hover { background: var(--surface-2); }
table.data th {
  position: sticky; top: 0; z-index: 2;
  background: var(--surface);
}

/* empty states were 46px of dead vertical space in a panel that is often short */
.empty { padding: 34px 20px; }
.empty svg { width: 32px; height: 32px; margin-bottom: 9px; }
.empty p { margin: 0; font-size: 12.5px; }

/* buttons in a page header line up on one baseline and never squash their labels */
.page-head__r .btn { white-space: nowrap; }

/* focus visibility across the console (keyboard operators + a11y) */
.btn:focus-visible, .icon-btn:focus-visible, .toggle:focus-visible,
select:focus-visible, input:focus-visible, textarea:focus-visible,
.vs-tag:focus-visible, .flt-chip:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}

/* =========================================================================================
   POLISH PASS — mobile
   ========================================================================================= */
@media (max-width: 880px) {
  /* Page-header actions: an even 2-up grid. `flex:1 1 auto` produced a ragged ladder where a
     lone long button (AutoPrice rules) took a whole row and the rest paired unevenly. */
  .page-head__r {
    display: grid; grid-template-columns: 1fr 1fr; gap: 8px; width: 100%;
  }
  .page-head__r > * { min-width: 0; }
  .page-head__r .btn { width: 100%; justify-content: center; flex: none; }
  .page-head__r form { display: contents; }          /* let a wrapped form's button join the grid */
  .page-head__r form .btn { width: 100%; }
  /* the primary action gets the full width, so the main CTA is never half a row */
  .page-head__r .btn.primary { grid-column: 1 / -1; }

  /* Panel heads stack: title line, then its controls as a full-width row. */
  .panel__head { flex-direction: column; align-items: stretch; gap: 10px; }
  .panel__head > .row { width: 100%; flex-wrap: wrap !important; }
  .panel__head .sub { align-self: flex-start; }

  /* Events toolbar inside the panel head: chips scroll on one line, sort + search stack. */
  .flt-chips {
    display: flex; width: 100%; overflow-x: auto; flex-wrap: nowrap;
    scrollbar-width: none; -ms-overflow-style: none; padding-bottom: 2px;
  }
  .flt-chips::-webkit-scrollbar { display: none; }
  .flt-chips .flt-chip { flex: none; min-height: 38px; }
  #eventSort { width: 100% !important; flex: 1 1 100% !important; }
  #eventFilter { width: 100%; flex: 1 1 100% !important; }

  /* Cards filter bar: each labelled group becomes ONE horizontally-scrolling line rather than
     wrapping — sixteen wrapped chips on a phone push the table most of a screen down. Overrides
     the desktop wrap rule, which is more specific than the .flt-chips reset above. */
  .cards-flt { padding: 9px 12px; gap: 8px; }
  .cards-flt .flt-chips { flex-wrap: nowrap; overflow-x: auto; }
  .cards-flt__lbl { width: 44px; padding-top: 11px; font-size: 9.5px; }
  /* 2-up, not full-width: four stacked selects push the table most of a screen down, and these are
     narrowings the operator reaches for AFTER the chips. The label takes its own line so the pairs
     line up evenly — sharing the first line with it leaves one select stretched to 1.7x the rest. */
  .cards-flt__row--sel .cards-flt__lbl { flex: 1 1 100%; padding-top: 0; }
  .cards-flt__row--sel select,
  .cards-flt__row--sel .btn-mini { flex: 1 1 calc(50% - 5px); min-width: 0; min-height: 38px;
    margin-left: 0; width: auto; }

  /* Bulk-selection bar: label on top, actions as an even 2-up grid. */
  #bulkBar { flex-direction: column; align-items: stretch !important; gap: 10px; }
  #bulkBar > .row { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  #bulkBar .btn { width: 100%; justify-content: center; }

  /* Sticky table headers are hidden in card mode; drop the sticky so it can't trap a z-index. */
  table.data th { position: static; }
}

@media (max-width: 640px) {
  /* Stat strip: 2-up on a phone reads far better than 1-up scrolling forever. */
  .statline { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .stat.slim { padding: 11px 12px 10px; }
  .stat.slim .stat__value { font-size: 20px; }

  /* Fleet HUD: tighter, and the title never wraps away from the hamburger. */
  .fleet__title { font-size: 12.5px; }
  .chip { font-size: 11px; padding: 4px 9px; }

  /* Page title + description tighten up so the first panel is nearer the fold. */
  h1 { font-size: 21px; }
  .page-head { gap: 12px; margin-bottom: 14px; }
  .panel__body { padding: 14px; }

  /* Provisioning command blocks: the copy button goes under the command, full width. */
  .cmd__row { flex-direction: column; }
  .cmd__btn { width: 100%; }
  .cmd__code { font-size: 11.5px; }
  .provision__head { gap: 10px; }
  .provision__titles .sub { font-size: 12px; }
}
