/* ============================================================
   Lumi Admin — Mobbin design system
   (getdesign: `npx getdesign@latest add mobbin`, see DESIGN.md)

   A gallery-white, monochrome console. Near-black ink on a pure
   white canvas; hierarchy is built from a ladder of barely-there
   neutral tints and 1px hairlines instead of shadows and colour.
   Every interactive element is a stadium pill; containers sit at
   24px, media and fields at 16px. Type is Inter at the Saans
   weight positions — 650 headings, 450 text, 600 labels, 300 lead.

   Two deliberate extensions to the source system, both documented
   where they appear:
   1. Semantic status colours. Mobbin ships none — it is a marketing
      surface. An operator console cannot say "provider down" in
      grey, so a restrained, low-chroma set is defined and spent
      only on small pills and alert rows.
   2. A 14px/600 button label. Mobbin's `link` role is 16/600; at
      admin density (buttons inside table rows) that reads as a
      landing page, so the standard button drops one step and the
      page-level CTA (`.btn.lg`) keeps 16/600.
   ============================================================ */

:root {
  /* ---------- Mobbin primitives ---------- */
  --canvas: #ffffff;          /* page and card default */
  --canvas-soft: #f3f3f3;     /* the workhorse 6% ink wash */
  --field: #f0f0f0;           /* 8% wash: form fills */
  --hairline-soft: #f0f0f0;   /* faintest card outline */
  --hairline: #e0e0e0;        /* 16% control border */
  --ink: #141414;             /* the brand colour */
  --ink-soft: #262626;
  /* Mobbin specifies #707070. At 4.46:1 that misses AA on the
     canvas-soft tint it constantly sits on here — table headers,
     KPI labels, inactive segments. Darkened by five units, which
     is invisible on screen and clears 4.8:1 on every surface. */
  --text-muted: #6b6b6b;
  --text-faint: #adadad;
  --accent: #0066ff;          /* scarce: attention signals only */

  --primary: var(--ink);
  --primary-hover: #000000;
  --primary-focus: var(--ink);
  --on-primary: #ffffff;

  /* ---------- compatibility aliases ----------
     Page templates carry their own <style> blocks written against
     the previous token names. They keep working: the names are
     kept, the values are re-pointed onto the Mobbin tint ladder. */
  --surface-1: var(--canvas);
  --surface-2: var(--canvas-soft);
  --surface-3: #ebebeb;
  --surface-4: #e4e4e4;
  --hairline-strong: #d6d6d6;
  --hairline-tertiary: #c4c4c4;
  --ink-muted: var(--ink-soft);
  --ink-subtle: var(--text-muted);
  --ink-tertiary: var(--text-faint);
  --primary-soft: var(--canvas-soft);
  --primary-soft-2: #ebebeb;

  /* ---------- semantic (extension, see header) ----------
     Chosen dark enough to clear 4.5:1 on their own tint, and low
     enough in chroma to sit beside a monochrome page without
     turning it into a dashboard from 2014. */
  --success: #12653a;
  --success-bg: #eaf3ed;
  --warning: #7a5310;
  --warning-bg: #f7f0e3;
  --danger: #b3261e;
  --danger-bg: #fbebea;
  --info: #0b4ec9;
  --info-bg: #e9f0ff;

  /* ---------- radii ----------
     rounded.sm 16 · rounded.md 24 · full. The two smaller steps
     exist for chips and inline controls that would look like
     lozenges at 16. */
  --r-xs: 8px;
  --r-sm: 12px;
  --r-md: 16px;
  --r-lg: 24px;
  --r-xl: 24px;
  --r-card: 24px;
  --r-input: 16px;
  --r-pill: 9999px;
  --r-squircle: 30%;

  /* ---------- elevation ----------
     The system is shadow-free. These exist only for surfaces that
     genuinely float over content — the active segment of a
     segmented control, overflow panels, the mobile sheet. */
  --shadow-sm: none;
  --shadow-md: 0 2px 4px rgba(20, 20, 20, 0.04), 0 12px 32px rgba(20, 20, 20, 0.10);
  --shadow-lg: 0 4px 8px rgba(20, 20, 20, 0.05), 0 24px 64px rgba(20, 20, 20, 0.16);
  --shadow-pill: 0 1px 2px rgba(20, 20, 20, 0.06), 0 2px 8px rgba(20, 20, 20, 0.06);

  /* ---------- type ----------
     Saans is commercial; Inter is the substitute the system names.
     InterVariable carries the continuous weight axis that 650/450
     need — static Inter rounds them to 700/500, which still reads. */
  --font-display: "InterVariable", "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  --font-text: "InterVariable", "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  --font-mono: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, Consolas, monospace;

  --w-heading: 650;
  --w-title: 600;
  --w-body: 450;
  --w-light: 300;

  /* ---------- layout ---------- */
  --sidebar-w: 248px;
  --topbar-h: 72px;

  /* Telegram viewport insets, written by miniapp.js. */
  --app-safe-top: 0px;
  --app-safe-right: 0px;
  --app-safe-bottom: 0px;
  --app-safe-left: 0px;
  --app-content-safe-top: 0px;
  --app-content-safe-right: 0px;
  --app-content-safe-bottom: 0px;
  --app-content-safe-left: 0px;
}

/* ============ reset ============ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }

html {
  color-scheme: light;
  scroll-padding-top: calc(var(--topbar-h) + 16px);
}

body {
  font-family: var(--font-text);
  font-size: 14px;
  font-weight: var(--w-body);
  line-height: 1.43;
  letter-spacing: 0;              /* the grotesque is trusted at its natural fit */
  color: var(--ink);
  background: var(--canvas);      /* flat: no gradients on chrome */
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a { color: inherit; text-decoration: none; transition: color 150ms ease; }
button { font: inherit; cursor: pointer; }
input, select, textarea { font: inherit; color: inherit; }

/* Inline links inside content read as Mobbin's underlined muted
   links — in a monochrome page a hover colour change alone is
   invisible. Scoped to table cells and prose: a link that is itself
   a row or a card (menu rows, result tiles) is already a target and
   an underline across it would only add noise. */
main td a:not([class]),
main p a:not([class]) {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--hairline);
  text-underline-offset: 3px;
}
main td a:not([class]):hover,
main p a:not([class]):hover { text-decoration-color: var(--ink); }

a:focus-visible,
button:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--ink);   /* focus is signalled in ink */
  outline-offset: 3px;
  border-radius: var(--r-xs);
}

a, button, summary, input, select, textarea {
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(20, 20, 20, 0.06);
}

/* Screen-reader-only text: icon-only controls keep their label. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ============ typography ============
   Weight contrast is the drama: 650 headings against 450 text and
   300 lead paragraphs. Tight leading up top, no tracking anywhere,
   sentence case throughout — never all-caps. */
h1 {
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: var(--w-heading);
  line-height: 1.13;
  color: var(--ink);
  text-wrap: balance;
  margin-bottom: 20px;
}
h2 {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: var(--w-title);
  line-height: 1.3;
  color: var(--ink);
  margin: 48px 0 16px;
}
h3 {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: var(--w-title);
  line-height: 1.38;
  color: var(--ink);
}
h4 {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: var(--w-title);
  line-height: 1.43;
  color: var(--ink);
}
h1, h2, h3 { scroll-margin-top: calc(var(--topbar-h) + 24px); }

p { line-height: 1.43; }

code {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink);
  background: var(--field);
  padding: 2px 7px;
  border-radius: var(--r-xs);
}

.muted { color: var(--text-muted); }
.right { text-align: right; }
.small { font-size: 12px; }

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

/* ============ sidebar ============
   `ex-app-shell-row`: rows on canvas, the active row taking the
   brand primary as its indicator — here the full polarity flip, an
   ink pill, which is the only "selected" signal a monochrome system
   has that survives a glance. */
.sidebar {
  position: sticky;
  top: 0;
  height: 100vh;
  padding: 24px 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  overflow-y: auto;
  background: var(--canvas);
  border-right: 1px solid var(--hairline-soft);
}
.sidebar .brand {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 4px 8px 24px;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: var(--w-title);
  line-height: 1.38;
  color: var(--ink);
}

/* The recurring iOS-squircle icon tile, at 30% corner radius. */
.brand-mark {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: 0 0 32px;
  border-radius: var(--r-squircle);
  background: var(--ink);
  color: var(--on-primary);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: var(--w-heading);
  line-height: 1;
}

.sidebar .nav-section {
  padding: 20px 12px 6px;
  color: var(--text-muted);
  font-size: 12px;
  font-weight: var(--w-title);
  line-height: 1.33;
  letter-spacing: 0;
  text-transform: none;          /* the system runs in sentence case */
}
.sidebar .nav-list { list-style: none; display: flex; flex-direction: column; gap: 2px; }
.sidebar .nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 40px;
  padding: 8px 12px;
  border-radius: var(--r-md);
  color: var(--ink-soft);
  font-size: 14px;
  font-weight: var(--w-title);
  transition: background 140ms ease, color 140ms ease;
}
.sidebar .nav-item:hover { background: var(--canvas-soft); color: var(--ink); }
.sidebar .nav-item.active {
  background: var(--ink);
  color: var(--on-primary);
}
.sidebar .nav-item .nav-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: var(--text-muted);
}
.sidebar .nav-item:hover .nav-icon { color: var(--ink); }
.sidebar .nav-item.active .nav-icon { color: var(--on-primary); }
.sidebar .nav-item .nav-label { flex: 1; min-width: 0; }
.sidebar .nav-item .nav-chev {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  color: var(--text-faint);
}
.sidebar .nav-item.active .nav-chev { color: rgba(255, 255, 255, 0.6); }

.sidebar-foot {
  margin-top: auto;
  padding: 20px 12px 4px;
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.33;
}
.sidebar-foot .dot {
  display: inline-grid;
  place-items: center;
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  border-radius: var(--r-squircle);
  background: var(--canvas-soft);
  color: var(--ink);
  font-size: 10px;
  font-weight: var(--w-heading);
}

/* ============ workspace ============ */
.workspace {
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: var(--canvas);
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  min-height: var(--topbar-h);
  padding: 16px 32px;
  display: flex;
  align-items: center;
  gap: 20px;
  background: var(--canvas);
  border-bottom: 1px solid var(--hairline-soft);
}
.topbar .crumbs {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  font-size: 14px;
}
.topbar .crumb-section {
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: var(--w-title);
  line-height: 1.38;
  white-space: nowrap;
}
.topbar .crumbs .sep { color: var(--text-faint); }
.topbar .crumbs .here { color: var(--text-muted); }
.topbar .spacer { flex: 1; }

.workspace main {
  flex: 1;
  min-width: 0;
  width: min(100%, 1320px);
  padding: 32px 32px 64px;
}

/* Full-bleed ink band with rounded top corners: the page's
   end-stop, and the system's one moment of polarity inversion. */
.app-footer {
  margin-top: auto;
  padding: 28px 32px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--ink);
  color: var(--on-primary);
}
.app-footer .app-footer-mark {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: var(--w-heading);
  line-height: 1.3;
}
.app-footer .brand-mark {
  background: var(--on-primary);
  color: var(--ink);
}
.app-footer small {
  color: var(--text-faint);
  font-size: 12px;
  line-height: 1.33;
}

/* ============ cards ============
   `pricing-card`: white fill, the faintest possible 1px edge, 24px
   corners, generous padding keeping content off the hairline. */
.card {
  padding: 24px;
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-card);
  background: var(--canvas);
  box-shadow: none;
}
.card > h2:first-child,
.card > h3:first-child { margin-top: 0; }

/* `pricing-card-featured`: emphasis by tint, never by outline. Used
   for the panel that frames a decision rather than data. */
.card.glass {
  background: var(--canvas-soft);
  border-color: transparent;
}

/* `ex-empty-state-card` */
.card.empty {
  padding: 48px 24px;
  background: var(--canvas-soft);
  border-color: transparent;
  color: var(--text-muted);
  text-align: center;
}

/* ============ grid ============ */
.grid { display: grid; gap: 16px; }
.grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid.cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.grid.cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
@media (max-width: 1180px) {
  .grid.cols-5, .grid.cols-6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .grid.cols-2, .grid.cols-3, .grid.cols-4,
  .grid.cols-5, .grid.cols-6 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .grid.cols-2, .grid.cols-3, .grid.cols-4,
  .grid.cols-5, .grid.cols-6 { grid-template-columns: 1fr; }
}

/* ============ KPI tile ============ */
.kpi .label {
  color: var(--text-muted);
  font-size: 14px;
  font-weight: var(--w-body);
}
.kpi .value {
  margin-top: 12px;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: var(--w-heading);
  line-height: 1.13;
  font-variant-numeric: tabular-nums;
}
.kpi .delta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.33;
  font-variant-numeric: tabular-nums;
}
.kpi .delta.up { color: var(--success); }
.kpi .delta.down { color: var(--danger); }
.kpi .delta.up::after,
.kpi .delta.down::after {
  content: "";
  display: inline-block;
  width: 10px;
  height: 10px;
  background: currentColor;
  -webkit-mask: var(--arrow) center / contain no-repeat;
          mask: var(--arrow) center / contain no-repeat;
}
.kpi .delta.up { --arrow: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='currentColor' d='M3 13l5-7 5 7H3z'/></svg>"); }
.kpi .delta.down { --arrow: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='currentColor' d='M3 3h10l-5 7-5-7z'/></svg>"); }

/* The single emphasised tile flips polarity rather than taking a
   colour — the same move as the footer and the active nav row. */
.kpi.primary {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--on-primary);
}
.kpi.primary .label,
.kpi.primary .delta { color: rgba(255, 255, 255, 0.72); }
.kpi.primary .value { color: var(--on-primary); }

/* Legacy colour-coded tiles collapse into the tint ladder: the
   system has no decorative hues to give them. */
.kpi.mint, .kpi.teal, .kpi.sky, .kpi.cyan,
.kpi.lilac, .kpi.peach, .kpi.cream {
  background: var(--canvas-soft);
  border-color: transparent;
}

/* ============ tables ============
   `ex-data-table-cell`: canvas-soft header, caption type, body-sm
   rows, hairline rules. Sentence case — no mono-caps eyebrow. */
table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  overflow: hidden;
  background: var(--canvas);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-card);
}
th, td {
  padding: 12px 16px;
  text-align: left;
  vertical-align: middle;
}
th {
  background: var(--canvas-soft);
  color: var(--text-muted);
  font-size: 12px;
  font-weight: var(--w-title);
  line-height: 1.33;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
}
td {
  border-top: 1px solid var(--hairline-soft);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.43;
}
tbody tr { transition: background 140ms ease; }
tbody tr:hover { background: var(--canvas-soft); }
td.num, th.right, td.right { text-align: right; }
td.num { font-variant-numeric: tabular-nums; }

/* A table that lives inside a card is already framed: it drops its
   own chrome and rides the card's padding. */
.card > table {
  margin-top: 12px;
  background: transparent;
  border: none;
  border-radius: 0;
}
.card > table th {
  padding-left: 0;
  padding-right: 0;
  background: transparent;
  border-bottom: 1px solid var(--hairline);
}
.card > table td { padding-left: 0; padding-right: 0; }
.card > table tbody tr:hover { background: transparent; }

/* Label/value pairs — a definition list that happens to be a table. */
table.kv {
  border: none;
  border-radius: 0;
  background: transparent;
}
table.kv th {
  width: 220px;
  padding-left: 0;
  background: transparent;
  color: var(--text-muted);
  font-size: 14px;
  font-weight: var(--w-body);
  white-space: normal;
}
table.kv td { padding-right: 0; }
table.kv tbody tr:hover { background: transparent; }
table.kv th, table.kv td { border-top: 1px solid var(--hairline-soft); }
table.kv tr:first-child th, table.kv tr:first-child td { border-top: none; }

/* ============ pills & badges ============
   Stadium at every size; `label` type; tint fill, no border. */
.pill {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--canvas-soft);
  color: var(--ink-soft);
  font-size: 12px;
  font-weight: var(--w-title);
  line-height: 1.33;
  white-space: nowrap;
}
.pill.green  { background: var(--success-bg); color: var(--success); }
.pill.amber  { background: var(--warning-bg); color: var(--warning); }
.pill.red,
.pill.orange { background: var(--danger-bg);  color: var(--danger); }
.pill.blue   { background: var(--info-bg);    color: var(--info); }
.pill.grey   { background: var(--canvas-soft); color: var(--text-muted); }

/* `badge-popular` — the one place the accent blue is allowed to
   interrupt: it is asking for a decision. */
.badge-accent {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--on-primary);
  font-size: 12px;
  font-weight: var(--w-title);
  line-height: 1.33;
}

/* ============ page header ============ */
.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  margin-bottom: 8px;
}
.page-head h1 { margin: 0; }
.page-head > form { margin: 0; }

/* One line of orientation under a title, set in the light 300
   counterpoint to the 650 heading above it. */
.page-note {
  max-width: 760px;
  margin: 12px 0 24px;
  color: var(--text-muted);
  font-size: 16px;
  font-weight: var(--w-light);
  line-height: 1.38;
}

.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 48px 0 16px;
}
.section-head h2 { margin: 0; }

/* A single headline number inside a card. */
.big-value {
  margin-top: 12px;
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: var(--w-heading);
  line-height: 1.13;
  font-variant-numeric: tabular-nums;
}
.big-value.low { color: var(--danger); }
.big-value + .big-value-note { margin-top: 6px; color: var(--text-muted); }

/* Bulk paste: one record per line. */
.paste-pool {
  width: 100%;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.5;
}

/* ============ forms ============
   `text-input`: a tint fill with no border at rest. The border
   appears only as the 2px ink focus ring. */
input[type=text],
input[type=password],
input[type=number],
input[type=date],
input[type=search],
input[type=email],
select,
textarea,
.input {
  width: 100%;
  min-height: 44px;
  padding: 11px 16px;
  border: none;
  border-radius: var(--r-input);
  background: var(--field);
  color: var(--ink);
  font-size: 14px;
  line-height: 1.43;
  transition: box-shadow 140ms ease, background 140ms ease;
}
input::placeholder, textarea::placeholder { color: var(--text-faint); }

input:hover:not(:focus),
select:hover:not(:focus),
textarea:hover:not(:focus) { background: #ebebeb; }

input:focus, select:focus, textarea:focus, .input:focus {
  outline: none;
  background: var(--field);
  box-shadow: inset 0 0 0 2px var(--ink);
}

select {
  appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23707070' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><path d='M4 6.5l4 4 4-4'/></svg>");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 16px;
}
textarea { min-height: 112px; line-height: 1.5; }

input[type=checkbox], input[type=radio] {
  width: auto;
  min-height: 0;
  accent-color: var(--ink);
}

/* A tint fill on a tinted surface disappears. Inside soft cards,
   sheets and auth panels the field takes the white canvas instead —
   the same 1-step separation, read the other way round. */
.card.glass input, .card.glass select, .card.glass textarea, .card.glass .input,
.card.empty input, .card.empty select, .card.empty textarea,
.advanced input, .advanced select, .advanced textarea, .advanced .input,
.telegram-auth input, .telegram-auth select,
.login-box input, .login-box select, .login-box textarea,
.search-product input, .search-product select {
  background: var(--canvas);
}
.card.glass input:hover:not(:focus), .card.glass select:hover:not(:focus), .card.glass textarea:hover:not(:focus),
.advanced input:hover:not(:focus), .advanced select:hover:not(:focus), .advanced textarea:hover:not(:focus),
.login-box input:hover:not(:focus) {
  background: #fafafa;
}
.card.glass input:focus, .card.glass select:focus, .card.glass textarea:focus,
.advanced input:focus, .advanced select:focus, .advanced textarea:focus,
.telegram-auth input:focus,
.login-box input:focus, .login-box select:focus, .login-box textarea:focus {
  background: var(--canvas);
}

label {
  display: block;
  margin-bottom: 8px;
  color: var(--text-muted);
  font-size: 12px;
  font-weight: var(--w-title);
  line-height: 1.33;
}

input[type=file] {
  min-height: 0;
  padding: 0;
  background: transparent;
  color: var(--text-muted);
  font-size: 14px;
}
input[type=file]::file-selector-button {
  margin-right: 12px;
  height: 36px;
  padding: 0 16px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  background: var(--canvas);
  color: var(--ink);
  font-family: inherit;
  font-size: 14px;
  font-weight: var(--w-title);
  cursor: pointer;
}

/* ============ buttons ============
   `button-primary` is the single CTA style: an ink pill. A
   rectangular button does not exist in this system. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 40px;
  padding: 8px 18px;
  border: 1px solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--ink);
  color: var(--on-primary);
  font-size: 14px;
  font-weight: var(--w-title);
  line-height: 1.43;
  white-space: nowrap;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease, transform 140ms ease;
}
.btn:hover { background: var(--primary-hover); border-color: var(--primary-hover); color: var(--on-primary); }
.btn:active { transform: translateY(0.5px); }
.btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* The page-level CTA keeps the system's own 16/600 `link` label. */
.btn.lg { min-height: 48px; padding: 12px 24px; font-size: 16px; }

/* `button-outline` — the de-emphasised twin, used when two actions
   sit side by side. */
.btn.muted, .btn.ghost {
  background: var(--canvas);
  border-color: var(--hairline);
  color: var(--ink);
}
.btn.muted:hover, .btn.ghost:hover {
  background: var(--canvas-soft);
  border-color: var(--hairline);
  color: var(--ink);
}

/* `button-pill-soft` — tertiary utility pill, no border. */
.btn.soft {
  background: var(--canvas-soft);
  border-color: transparent;
  color: var(--ink);
}
.btn.soft:hover { background: #ebebeb; border-color: transparent; color: var(--ink); }

/* Destructive actions state their consequence in the label; the
   colour only confirms it, and only fills once the pointer is on it. */
.btn.red {
  background: var(--canvas);
  border-color: var(--danger);
  color: var(--danger);
}
.btn.red:hover { background: var(--danger); border-color: var(--danger); color: var(--on-primary); }

/* ============ list screens ============
   `.listbar` — the per-section search form — is gone: one global
   search finds a customer or an asset from any screen, and a second
   field on every list was both a duplicate and the widest thing on
   a phone. What remains is `.filters`, further down. */
.toolbar {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 24px;
}
.toolbar input,
.toolbar select { max-width: 260px; }

.pager {
  margin-top: 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  color: var(--text-muted);
  font-size: 12px;
}
.pager .pages { display: flex; gap: 8px; }

.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

/* A row form does not fit a 280px panel: stack it. */
.more-panel .action-form { flex-direction: column; align-items: stretch; }
.more-panel .action-form > .label { min-width: 0; }
.more-panel .action-form input[type=text],
.more-panel .action-form input[type=number] { flex: 1 1 auto; width: 100%; }

/* ============ overflow menu («•••») ============
   Where the rare operations live, so an object card can lead with
   the one action the operator actually came for. */
.more { position: relative; display: inline-block; }
.more > summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  background: var(--canvas);
  color: var(--text-muted);
  font-size: 15px;
  cursor: pointer;
  user-select: none;
  transition: background 140ms ease, color 140ms ease;
}
.more > summary::-webkit-details-marker { display: none; }
.more > summary::marker { content: ""; }
.more > summary:hover { background: var(--canvas-soft); color: var(--ink); }
.more[open] > summary { background: var(--ink); border-color: var(--ink); color: var(--on-primary); }

/* `ex-modal-card`: the one surface the system lets lift off the page. */
.more-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  z-index: 30;
  min-width: 280px;
  max-width: min(92vw, 420px);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-card);
  background: var(--canvas);
  box-shadow: var(--shadow-md);
}
.more-panel > form { margin: 0; }
.more-panel > form + form { border-top: 1px solid var(--hairline-soft); padding-top: 12px; }
@media (max-width: 640px) {
  .more-panel { min-width: 0; width: max-content; max-width: calc(100vw - 28px); }
}

/* ============ «Дополнительно» ============
   `faq-row`: a full-width soft bar that opens. Technical
   parameters and bulk operations are present without competing
   with the daily controls. */
.advanced {
  margin-top: 24px;
  border-radius: var(--r-md);
  background: var(--canvas-soft);
}
.advanced > summary {
  padding: 14px 20px;
  color: var(--ink);
  font-size: 14px;
  font-weight: var(--w-title);
  cursor: pointer;
  user-select: none;
  border-radius: var(--r-md);
}
.advanced > summary::-webkit-details-marker { display: none; }
.advanced > summary::marker { content: ""; }
.advanced > summary::after {
  content: "";
  float: right;
  width: 16px;
  height: 16px;
  margin-top: 2px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>") center / contain no-repeat;
          mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>") center / contain no-repeat;
  transition: transform 160ms ease;
}
.advanced[open] > summary::after { transform: rotate(180deg); }
.advanced-body { padding: 4px 20px 20px; }

details.helper { color: var(--text-muted); font-size: 12px; }
details.helper summary { cursor: pointer; padding: 6px 0; }
details.helper code {
  display: block;
  margin-top: 8px;
  padding: 12px 14px;
  border-radius: var(--r-md);
  background: var(--canvas-soft);
  color: var(--ink);
  white-space: pre;
  overflow-x: auto;
}

/* Raw event payloads: worth reading once, noise the rest of the time. */
.meta-dump summary { cursor: pointer; color: var(--text-muted); font-size: 12px; }
.meta-dump summary:hover { color: var(--ink); }
.meta-dump code {
  display: block;
  margin-top: 8px;
  max-width: 100%;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-all;
  font-size: 11px;
  color: var(--ink-soft);
}

/* ============ segmented control ============
   `segmented-control`: a soft stadium track holding pill options;
   the active one is a white pill that lifts — the system's single
   sanctioned shadow. */
.tabs {
  display: flex;
  gap: 4px;
  width: max-content;
  max-width: 100%;
  margin: 0 0 16px;
  padding: 4px;
  border-radius: var(--r-pill);
  background: var(--canvas-soft);
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  flex: 0 0 auto;
  min-height: 34px;
  padding: 6px 16px;
  border: none;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-text);
  font-size: 14px;
  font-weight: var(--w-title);
  cursor: pointer;
  white-space: nowrap;
  transition: background 140ms ease, color 140ms ease;
}
.tab:hover { color: var(--ink); }
.tab[aria-selected="true"] {
  background: var(--canvas);
  color: var(--ink);
  box-shadow: var(--shadow-pill);
}
.tab .count { margin-left: 6px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.tab[aria-selected="true"] .count { color: var(--text-muted); }

/* ============ alerts ============ */
.alert {
  display: block;
  margin-bottom: 12px;
  padding: 14px 18px;
  border-radius: var(--r-md);
  background: var(--canvas-soft);
  color: var(--ink-soft);
  font-size: 14px;
  font-weight: var(--w-body);
  line-height: 1.43;
}
.alert.info { background: var(--info-bg); color: var(--info); }
.alert.success, .alert.green { background: var(--success-bg); color: var(--success); }
.alert.warning, .alert.amber { background: var(--warning-bg); color: var(--warning); }
.alert.error, .alert.red, .alert.danger { background: var(--danger-bg); color: var(--danger); }

/* ============ misc data chrome ============ */
.routing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 24px;
}
.routing-col h4 { margin: 0 0 4px; display: flex; align-items: center; gap: 8px; }
.routing-col .cnt { color: var(--text-muted); font-weight: var(--w-body); font-size: 12px; }
.routing-col .zones { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.zone-chip {
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--canvas-soft);
  color: var(--ink-soft);
  font-family: var(--font-mono);
  font-size: 11px;
}
.routing-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; background: var(--text-faint); }
.routing-dot.nicenic { background: var(--ink); }
.routing-dot.namesilo { background: var(--info); }
.routing-dot.dynadot { background: var(--success); }
.routing-dot.manual { background: var(--text-faint); }

.chart { position: relative; height: 280px; }

.funnel-step { display: flex; align-items: center; gap: 16px; margin-bottom: 10px; }
.funnel-step .name { flex: 0 0 240px; color: var(--ink); }
.funnel-step .bar { flex: 1; height: 8px; min-width: 4px; border-radius: var(--r-pill); background: var(--ink); }
.funnel-step .pct { flex: 0 0 80px; text-align: right; color: var(--text-muted); font-size: 12px; font-variant-numeric: tabular-nums; }

.cohort-cell {
  display: inline-block;
  padding: 4px 8px;
  border-radius: var(--r-xs);
  color: var(--ink);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.alert-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 8px 16px;
  border-radius: var(--r-pill);
  background: var(--canvas-soft);
  color: var(--ink-soft);
  font-size: 14px;
  font-weight: var(--w-title);
}
.alert-pill.green { background: var(--success-bg); color: var(--success); }
.alert-pill.amber { background: var(--warning-bg); color: var(--warning); }
.alert-pill.red,
.alert-pill.orange { background: var(--danger-bg); color: var(--danger); }
.alert-pill.blue { background: var(--info-bg); color: var(--info); }
.alert-pill.grey { background: var(--canvas-soft); color: var(--text-muted); }

.skip-link {
  position: fixed;
  z-index: 100;
  top: 12px;
  left: 12px;
  padding: 12px 20px;
  border-radius: var(--r-pill);
  background: var(--ink);
  color: var(--on-primary);
  font-weight: var(--w-title);
  transform: translateY(-200%);
  transition: transform 140ms ease;
}
.skip-link:focus { transform: translateY(0); }

/* ============ topbar search ============
   A control in the navigation chrome, so it takes the pill rather
   than the 16px field geometry. */
.topbar-search {
  display: flex;
  align-items: center;
  flex: 0 1 380px;
  min-width: 220px;
  max-width: 380px;
  margin-left: auto;
}
.topbar-search input[type=search] {
  min-height: 40px;
  height: 40px;
  padding: 8px 84px 8px 16px;
  border-radius: var(--r-pill);
  background: var(--field);
  font-size: 14px;
}
.topbar-search button {
  width: 72px;
  height: 32px;
  margin-left: -76px;
  padding: 0;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--ink);
  color: var(--on-primary);
  font: inherit;
  font-size: 12px;
  font-weight: var(--w-title);
  cursor: pointer;
}
.topbar-search button:hover { background: var(--primary-hover); }

/* ============ owner search ============ */
.search-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(360px, 0.9fr);
  gap: 32px;
  align-items: end;
  margin-bottom: 24px;
}
.search-hero h1 { margin: 4px 0 8px; }
.search-hero .eyebrow {
  margin: 0;
  color: var(--text-muted);
  font-size: 12px;
  font-weight: var(--w-title);
  line-height: 1.33;
  letter-spacing: 0;
  text-transform: none;
}
.search-hero .muted {
  margin: 0;
  color: var(--text-muted);
  font-size: 16px;
  font-weight: var(--w-light);
  line-height: 1.38;
}
.owner-search-form label { margin-bottom: 8px; }
.owner-search-field { display: flex; gap: 8px; }
.owner-search-field input { min-width: 0; }

.search-status { min-height: 24px; margin: 12px 0 16px; color: var(--text-muted); font-size: 14px; }
.search-spinner {
  display: inline-block;
  width: 12px;
  height: 12px;
  margin-right: 8px;
  border: 2px solid var(--hairline);
  border-top-color: var(--ink);
  border-radius: 50%;
  vertical-align: -2px;
  animation: search-spin 700ms linear infinite;
}
@keyframes search-spin { to { transform: rotate(360deg); } }

.search-product-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  align-items: start;
}
.search-product { padding: 20px; min-width: 0; }
.search-product-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}
.search-product-heading h2 { margin: 0; font-size: 20px; }
.search-group-title {
  margin: 20px 0 8px;
  color: var(--text-muted);
  font-size: 12px;
  font-weight: var(--w-title);
  line-height: 1.33;
  letter-spacing: 0;
  text-transform: none;
}
.search-customer-grid,
.search-result-list { display: grid; gap: 8px; }

.search-customer-card,
.search-result-card {
  display: flex;
  min-width: 0;
  border-radius: var(--r-md);
  background: var(--canvas-soft);
  color: var(--ink);
  text-decoration: none;
  transition: background 140ms ease, transform 140ms ease;
}
.search-customer-card:hover,
.search-result-card:hover { background: #ebebeb; transform: translateY(-1px); }
.search-customer-card:focus-visible,
.search-result-card:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.search-customer-card {
  flex-direction: column;
  gap: 4px;
  padding: 14px 16px;
  color: var(--text-muted);
  font-size: 12px;
}
.search-customer-card strong { color: var(--ink); font-size: 14px; font-weight: var(--w-title); }
.search-customer-card .pill { align-self: flex-start; margin-top: 4px; background: var(--canvas); }
.search-result-card { flex-direction: column; gap: 4px; padding: 12px 14px; }
.search-result-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}
.search-result-top strong { min-width: 0; overflow-wrap: anywhere; font-size: 14px; font-weight: var(--w-title); }
.search-result-top .pill { flex: 0 0 auto; background: var(--canvas); }
.search-result-subtitle,
.search-result-meta { overflow-wrap: anywhere; color: var(--text-muted); font-size: 12px; line-height: 1.33; }
.search-result-meta { color: var(--text-muted); }
.search-empty { margin: 4px 0 0; color: var(--text-muted); font-size: 12px; }
.search-product-error { border-color: var(--danger); }

.local-search-hero { align-items: center; }
.local-search-hero h1 { margin: 0 0 8px; }
.local-search-results { width: min(100%, 820px); grid-template-columns: 1fr; }
.local-search-results .search-customer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (max-width: 1320px) {
  .search-product-grid { grid-template-columns: 1fr; }
  .search-customer-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 1180px) {
  .topbar { flex-wrap: wrap; }
  .topbar-search { order: 5; flex: 1 0 100%; width: 100%; max-width: none; margin-left: 0; }
}
@media (max-width: 760px) {
  .search-hero { grid-template-columns: 1fr; gap: 20px; }
  .search-customer-grid { grid-template-columns: 1fr; }
}

/* ============ dashboard ============ */
.dashboard-page { width: min(100%, 1120px); margin: 0 auto; }
.dashboard-heading {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 32px;
  margin-bottom: 32px;
}
.dashboard-heading h1 {
  margin: 0 0 8px;
  font-size: clamp(32px, 3.4vw, 44px);
  line-height: 1.13;
}
.dashboard-heading p {
  max-width: 620px;
  color: var(--text-muted);
  font-size: 16px;
  font-weight: var(--w-light);
  line-height: 1.38;
}
.dashboard-period { display: grid; flex: 0 0 168px; gap: 8px; }
.dashboard-period label { margin: 0; }

.dashboard-summary > h2,
.dashboard-alerts > h2,
.dashboard-menu-section > h2 {
  margin: 0 0 12px;
  color: var(--ink);
  font-size: 20px;
  font-weight: var(--w-title);
  line-height: 1.3;
  text-transform: none;
}
.dashboard-kpis {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}
.dashboard-kpi {
  min-width: 0;
  min-height: 132px;
  padding: 24px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 12px;
  border-radius: var(--r-card);
  background: var(--canvas-soft);
}
/* Polarity inversion carries the lead figures — the same device as
   the footer band, spent on the two numbers that matter most. */
.dashboard-kpi-primary { background: var(--ink); color: var(--on-primary); }
.dashboard-kpi > span { color: var(--text-muted); font-size: 14px; }
.dashboard-kpi-primary > span { color: rgba(255, 255, 255, 0.72); }
.dashboard-kpi > strong {
  overflow: hidden;
  color: inherit;
  font-family: var(--font-display);
  font-size: clamp(26px, 2.8vw, 32px);
  font-weight: var(--w-heading);
  line-height: 1.13;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.dashboard-kpi > small { color: var(--text-muted); font-size: 12px; line-height: 1.33; }
.dashboard-kpi-primary > small { color: rgba(255, 255, 255, 0.64); }
.dashboard-kpi > small.up { color: var(--success); }
.dashboard-kpi > small.down { color: var(--danger); }
.dashboard-kpi-primary > small.up,
.dashboard-kpi-primary > small.down { color: rgba(255, 255, 255, 0.82); }

.dashboard-alerts { margin-top: 48px; }
.dashboard-alert-list { display: grid; gap: 8px; }
.dashboard-alert {
  min-height: 56px;
  padding: 14px 20px;
  display: flex;
  align-items: center;
  gap: 12px;
  border-radius: var(--r-md);
  background: var(--canvas-soft);
  color: var(--ink);
  font-size: 14px;
  font-weight: var(--w-title);
  transition: background 140ms ease;
}
.dashboard-alert:hover { background: #ebebeb; }
.dashboard-alert .nav-chev { width: 16px; height: 16px; margin-left: auto; color: var(--text-faint); }
.dashboard-alert.red { background: var(--danger-bg); color: var(--danger); }
.dashboard-alert.red .nav-chev { color: var(--danger); }
.dashboard-alert.amber { background: var(--warning-bg); color: var(--warning); }
.dashboard-alert.amber .nav-chev { color: var(--warning); }

.dashboard-menu-grid {
  margin-top: 48px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 40px 24px;
  align-items: start;
}
.dashboard-menu-list {
  overflow: hidden;
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-card);
  background: var(--canvas);
}
.dashboard-menu-list > a {
  min-height: 64px;
  padding: 12px 16px;
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) 16px;
  gap: 14px;
  align-items: center;
  color: var(--ink);
  font-size: 14px;
  font-weight: var(--w-title);
  transition: background 140ms ease;
}
.dashboard-menu-list > a + a { border-top: 1px solid var(--hairline-soft); }
.dashboard-menu-list > a:hover { background: var(--canvas-soft); }
/* `app-icon-squircle` — the 30% iOS silhouette, the system's
   recurring visual motif. */
.dashboard-menu-icon {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: var(--r-squircle);
  background: var(--canvas-soft);
  color: var(--ink);
}
.dashboard-menu-icon svg { width: 20px; height: 20px; }
.dashboard-menu-list > a:hover .dashboard-menu-icon { background: var(--canvas); }
.dashboard-menu-list .nav-chev { width: 16px; height: 16px; color: var(--text-faint); }

/* ============ authentication ============
   `ex-auth-form-card`: a soft-tinted card on the white canvas, no
   outline and no shadow. The screen deliberately has no fallback
   credentials — it only confirms a Telegram identity. */
body.login-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tg-stable-height, 100vh);
  padding:
    max(24px, env(safe-area-inset-top))
    max(18px, env(safe-area-inset-right))
    max(24px, env(safe-area-inset-bottom))
    max(18px, env(safe-area-inset-left));
  background: var(--canvas);
}
main.anon { width: 100%; display: flex; justify-content: center; }

.telegram-auth {
  width: min(420px, 100%);
  margin: auto;
  padding: 48px 32px 32px;
  border-radius: var(--r-card);
  background: var(--canvas-soft);
  text-align: center;
}
.telegram-auth-mark {
  display: inline-grid;
  place-items: center;
  width: 64px;
  height: 64px;
  margin-bottom: 24px;
  border-radius: var(--r-squircle);
  background: var(--ink);
  color: var(--on-primary);
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: var(--w-heading);
  line-height: 1;
}
.telegram-auth-kicker {
  margin-bottom: 12px;
  color: var(--text-muted);
  font-size: 12px;
  font-weight: var(--w-title);
  line-height: 1.33;
  letter-spacing: 0;
  text-transform: none;
}
.telegram-auth h1 { margin-bottom: 12px; font-size: clamp(28px, 8vw, 32px); }
.telegram-auth-status {
  min-height: 44px;
  color: var(--text-muted);
  font-size: 16px;
  font-weight: var(--w-light);
  line-height: 1.38;
}
.telegram-auth-loader { display: grid; place-items: center; height: 48px; margin: 16px 0 20px; }
.telegram-auth-loader span {
  width: 28px;
  height: 28px;
  border: 2px solid var(--hairline);
  border-top-color: var(--ink);
  border-radius: 50%;
  animation: telegram-auth-spin 760ms linear infinite;
}
.telegram-auth-hint {
  padding-top: 20px;
  border-top: 1px solid var(--hairline);
  color: var(--text-faint);
  font-size: 12px;
  line-height: 1.33;
}
.telegram-auth-hint code { background: var(--canvas); }
.telegram-auth-failed .telegram-auth-loader { display: none; }
.telegram-auth-failed .telegram-auth-status { color: var(--danger); }
@keyframes telegram-auth-spin { to { transform: rotate(360deg); } }

/* The password login card, where a product still exposes one. */
.login-box {
  width: min(380px, calc(100vw - 32px));
  padding: 32px;
  border-radius: var(--r-card);
  background: var(--canvas-soft);
}
.login-box h1 { margin-bottom: 24px; text-align: center; }
.login-box .login-subtitle {
  margin: -12px 0 24px;
  color: var(--text-muted);
  font-size: 16px;
  font-weight: var(--w-light);
  line-height: 1.38;
  text-align: center;
}
.login-error {
  margin-bottom: 16px;
  padding: 12px 16px;
  border-radius: var(--r-md);
  background: var(--danger-bg);
  color: var(--danger);
  font-size: 14px;
}
.login-box .row { margin-bottom: 16px; }
.login-box .btn { width: 100%; }

/* ============ data list ============
   The row that list screens are built from. A table is a desktop
   object: folded onto a phone, a nine-column row becomes nine
   stacked label/value lines, which is how a single traffic source
   came to fill a whole screen. A row states what the record is on
   the left, what it is worth on the right, and everything else on a
   muted second line — one glance, ~72px, and it keeps that shape on
   a wide screen where it simply gets more room. */
.data-list { display: grid; gap: 8px; }

/* Rows that belong to one object (a user's subscriptions, a source's
   last visitors) read better welded into a single framed block. */
.data-list.flush {
  gap: 0;
  overflow: hidden;
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-card);
}
.data-list.flush > .data-row { border: 0; border-radius: 0; }
.data-list.flush > .data-row + .data-row { border-top: 1px solid var(--hairline-soft); }

.data-row {
  min-height: 64px;
  padding: 12px 16px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px 12px;
  align-items: center;
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-md);
  background: var(--canvas);
  color: var(--ink);
  transition: background 140ms ease;
}
a.data-row:hover { background: var(--canvas-soft); }
a.data-row { grid-template-columns: minmax(0, 1fr) auto 16px; }
.data-row > .nav-chev {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  color: var(--text-faint);
}

.data-row-main { min-width: 0; display: grid; gap: 3px; }
.data-row-title {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-size: 15px;
  font-weight: var(--w-title);
  line-height: 1.33;
}
.data-row-title > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.data-row-meta {
  overflow: hidden;
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.33;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.data-row-meta code {
  padding: 0;
  background: none;
  font-size: 11px;
}

.data-row-side {
  display: grid;
  gap: 3px;
  justify-items: end;
  text-align: right;
}
.data-row-value {
  font-size: 15px;
  font-weight: var(--w-title);
  line-height: 1.33;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.data-row-sub {
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.33;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* A record judged by several numbers at once — a traffic source, a
   zone in the price book — puts them on their own line as a strip,
   rather than growing columns that squeeze the title off the row. */
.data-row.stacked { grid-template-columns: minmax(0, 1fr) auto; }
.data-row.stacked > .metric-strip,
.data-row.stacked > .row-action { grid-column: 1 / -1; }
/* The one control a record can carry inline (a status switch, a quick
   toggle) sits under it rather than in a squeezed last column. */
.row-action { display: flex; gap: 8px; margin-top: 12px; }
.row-action select { flex: 1 1 auto; min-width: 0; }
.row-action .btn { flex: 0 0 auto; }
/* A disclosure in that slot stays a disclosure — flex would put its
   summary and its body side by side. */
details.row-action { display: block; min-height: 0; }
.metric-strip { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.metric {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  background: var(--canvas-soft);
  font-size: 12px;
  line-height: 1.33;
  white-space: nowrap;
}
.metric > b { font-weight: var(--w-title); font-variant-numeric: tabular-nums; }
.metric > span { color: var(--text-muted); }
.metric.lead { background: var(--ink); color: var(--on-primary); }
.metric.lead > span { color: rgba(255, 255, 255, 0.72); }

/* ============ copy field ============
   A value the operator is here to take away — a referral link, a
   key. The value gets the whole width and truncates; the action is
   a pill under it, so a 60-character link never pushes the button
   off a phone screen. */
.copy-field {
  display: grid;
  gap: 10px;
  padding: 14px 16px;
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-md);
  background: var(--canvas);
}
.copy-field .label { color: var(--text-muted); font-size: 12px; line-height: 1.33; }
.copy-field .value {
  display: block;
  overflow: hidden;
  padding: 11px 14px;
  border-radius: var(--r-sm);
  background: var(--field);
  font-family: var(--font-mono);
  font-size: 13px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.copy-field .btn { justify-self: start; }
@media (min-width: 641px) {
  .copy-field { grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
  .copy-field .label { grid-column: 1 / -1; }
}

/* ============ metric board ============
   Six KPI tiles at 132px each is a desktop habit; on a phone it is
   three screens of chrome around six numbers. The board keeps the
   same figures in one hairline-divided card. */
.metric-board {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(116px, 1fr));
  gap: 1px;
  overflow: hidden;
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-card);
  background: var(--hairline-soft);
}
.metric-board > div { padding: 14px 16px; background: var(--canvas); }
.metric-board .delta {
  margin-top: 3px;
  color: var(--text-faint);
  font-size: 11px;
  line-height: 1.33;
}
/* On a phone the board is exactly two columns, so an odd count would leave
   one cell showing the hairline the gaps are painted with. The last tile
   takes the whole row instead. */
@media (max-width: 640px) {
  .metric-board { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .metric-board > div:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
.metric-board .label { color: var(--text-muted); font-size: 12px; line-height: 1.33; }
.metric-board .value {
  margin-top: 4px;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: var(--w-heading);
  line-height: 1.18;
  font-variant-numeric: tabular-nums;
}

/* ============ filter row ============
   Free-text lookup lives in exactly one place — the global search.
   What stays on a list screen is the narrowing an operator does
   while browsing, so it is a scroll strip of self-submitting chips,
   not a form with its own button and its own line. */
.filters {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px;
  overflow-x: auto;
  scrollbar-width: none;
}
.filters::-webkit-scrollbar { display: none; }
.filters > * { flex: 0 0 auto; }
.filters select,
.filters .input {
  width: auto;
  min-height: 38px;
  padding: 7px 34px 7px 14px;
  border-color: transparent;
  border-radius: var(--r-pill);
  background-color: var(--canvas-soft);
  font-size: 14px;
  font-weight: var(--w-title);
}
.filters .tabs { margin: 0; }

/* The "you are looking at one query" state, left behind when the
   global search hands a list screen a filter. */
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 38px;
  padding: 6px 6px 6px 14px;
  border-radius: var(--r-pill);
  background: var(--ink);
  color: var(--on-primary);
  font-size: 13px;
  font-weight: var(--w-title);
  white-space: nowrap;
}
.filter-chip .clear {
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.18);
  color: var(--on-primary);
  font-size: 15px;
  line-height: 1;
}
.filter-chip .clear:hover { background: rgba(255, 255, 255, 0.3); }

/* A segmented control whose options are links (a filter that lives
   in the URL) rather than script-driven tabs. */
a.tab { display: inline-flex; align-items: center; }
a.tab[aria-current="page"] {
  background: var(--canvas);
  color: var(--ink);
  box-shadow: var(--shadow-pill);
}

/* ============ bottom tab bar ============
   Reachability: on a phone the top-right corner is the furthest
   point from the thumb, and it is where both navigation controls
   used to sit. The five destinations an operator actually moves
   between now live in the bottom third of the screen, the way every
   mobile app they have ever used puts them. Destinations only —
   actions stay on their pages. Desktop keeps the sidebar and never
   renders this. */
.tabbar { display: none; }

/* ============================================================
   Telegram Mini App shell
   The console keeps its desktop density and becomes a
   thumb-friendly owner console inside Telegram. The palette does
   NOT follow the Telegram theme: this system is gallery-white by
   definition, and half-inheriting a dark client theme would leave
   ink text on a dark surface. Only the viewport and safe-area
   variables are taken from the client (written by miniapp.js).
   ============================================================ */
html.is-telegram { color-scheme: light; }
body.miniapp-page {
  min-height: var(--tg-stable-height, 100vh);
  padding-bottom: env(safe-area-inset-bottom);
  overscroll-behavior-y: none;
}

/* Controls that only exist once the shell folds. */
.sheet-close,
.sidebar-backdrop { display: none; }

/* ============ folded shell (≤900px) ============ */
@media (max-width: 900px) {
  body.miniapp-page { min-height: var(--tg-stable-height, 100dvh); padding-bottom: 0; }
  body.nav-sheet-open { overflow: hidden; }

  .app-shell { display: block; min-height: var(--tg-stable-height, 100dvh); }

  /* The navigation becomes a bottom sheet: `ex-modal-card` chrome,
     24px corners, the one surface allowed to float. */
  .sidebar {
    position: fixed;
    z-index: 60;
    top: auto;
    right: max(8px, var(--app-content-safe-right), env(safe-area-inset-right));
    bottom: max(8px, var(--app-content-safe-bottom), env(safe-area-inset-bottom));
    left: max(8px, var(--app-content-safe-left), env(safe-area-inset-left));
    width: auto;
    height: auto;
    max-height: min(78dvh, 680px);
    padding: 12px 12px 20px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    border: 1px solid var(--hairline-soft);
    border-right: 1px solid var(--hairline-soft);
    border-radius: var(--r-card);
    background: var(--canvas);
    box-shadow: var(--shadow-lg);
    transform: translateY(calc(100% + 32px));
    visibility: hidden;
    transition: transform 220ms cubic-bezier(.2, .8, .2, 1), visibility 220ms;
    -webkit-overflow-scrolling: touch;
  }
  body.nav-sheet-open .sidebar { transform: translateY(0); visibility: visible; }

  .sidebar .brand {
    flex: 0 0 auto;
    min-height: 48px;
    padding: 4px 4px 12px 8px;
    font-size: 16px;
  }
  .sheet-close {
    margin-left: auto;
    width: 44px;
    height: 44px;
    display: inline-grid;
    place-items: center;
    border: 1px solid var(--hairline);
    border-radius: var(--r-pill);
    background: var(--canvas);
    color: var(--text-muted);
  }
  .sheet-close:hover { background: var(--canvas-soft); color: var(--ink); }
  .sidebar .nav-section { display: block; padding: 16px 12px 6px; }
  .sidebar .nav-list { flex: 0 0 auto; flex-direction: column; width: 100%; gap: 2px; }
  .sidebar .nav-list li { width: 100%; }
  .sidebar .nav-item {
    min-height: 48px;
    width: 100%;
    padding: 12px 14px;
    border-radius: var(--r-md);
    white-space: normal;
  }
  .sidebar .nav-item .nav-chev { display: block; }
  .sidebar-foot { display: none; }

  .sidebar-backdrop {
    position: fixed;
    z-index: 55;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
    border: 0;
    background: rgba(20, 20, 20, 0.38);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 180ms ease, visibility 180ms;
  }
  body.nav-sheet-open .sidebar-backdrop { opacity: 1; visibility: visible; pointer-events: auto; }

  .workspace { min-height: var(--tg-stable-height, 100dvh); }

  .topbar {
    position: sticky;
    z-index: 30;
    top: 0;
    min-height: 0;
    padding:
      max(10px, var(--app-content-safe-top), env(safe-area-inset-top))
      max(16px, var(--app-content-safe-right), env(safe-area-inset-right))
      10px
      max(16px, var(--app-content-safe-left), env(safe-area-inset-left));
    display: grid;
    grid-template-columns: minmax(0, 1fr) 44px 44px;
    gap: 8px;
  }
  .topbar .crumbs {
    grid-column: 1;
    grid-row: 1;
    min-width: 0;
    display: grid;
    align-content: center;
    gap: 2px;
  }
  .topbar .crumb-section {
    overflow: hidden;
    font-size: 20px;
    font-weight: var(--w-heading);
    line-height: 1.3;
    text-overflow: ellipsis;
  }
  .topbar .crumbs .sep { display: none; }
  .topbar .crumbs .here {
    overflow: hidden;
    color: var(--text-muted);
    font-size: 12px;
    font-weight: var(--w-body);
    line-height: 1.33;
    letter-spacing: 0;
    text-transform: none;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .topbar .spacer { display: none; }

  .workspace main {
    width: 100%;
    padding:
      16px max(16px, var(--app-content-safe-right), env(safe-area-inset-right))
      calc(96px + max(var(--app-content-safe-bottom), env(safe-area-inset-bottom)))
      max(16px, var(--app-content-safe-left), env(safe-area-inset-left));
  }
  .app-footer {
    padding:
      24px max(16px, env(safe-area-inset-right))
      calc(24px + env(safe-area-inset-bottom))
      max(16px, env(safe-area-inset-left));
  }

  /* Touch targets: 44px minimum, 16px text so iOS does not zoom. */
  input[type=text],
  input[type=password],
  input[type=number],
  input[type=date],
  input[type=search],
  input[type=email],
  select,
  textarea,
  .input { min-height: 48px; padding: 13px 16px; font-size: 16px; }
  textarea { min-height: 128px; }
  .btn, .alert-pill, details > summary { min-height: 44px; }
  .btn { padding: 10px 18px; }

  .toolbar { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .toolbar > input,
  .toolbar > select,
  .toolbar > .input { grid-column: 1 / -1; max-width: none; }
  .toolbar > .btn { width: 100%; }

  main form[style*="display:flex"],
  main form[style*="display: flex"] {
    width: 100%;
    max-width: none !important;
    flex-wrap: wrap;
  }
  main form[style*="display:flex"] > input,
  main form[style*="display:flex"] > select,
  main form[style*="display: flex"] > input,
  main form[style*="display: flex"] > select { min-width: min(100%, 220px); flex: 1 1 220px; }

  h1 { font-size: 26px; }
  h2 { margin: 28px 0 12px; font-size: 18px; }

  .dashboard-page { max-width: 720px; }
  .dashboard-heading { align-items: center; margin-bottom: 24px; }
  .dashboard-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dashboard-alerts, .dashboard-menu-grid { margin-top: 36px; }
  .dashboard-menu-grid { grid-template-columns: 1fr; gap: 32px; }
  .local-search-results .search-customer-grid { grid-template-columns: 1fr; }

  /* ---- bottom tab bar ---- */
  .tabbar {
    position: fixed;
    z-index: 50;
    right: 0;
    bottom: 0;
    left: 0;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 2px;
    padding:
      6px max(6px, var(--app-content-safe-right), env(safe-area-inset-right))
      calc(6px + max(var(--app-content-safe-bottom), env(safe-area-inset-bottom)))
      max(6px, var(--app-content-safe-left), env(safe-area-inset-left));
    border-top: 1px solid var(--hairline-soft);
    background: rgba(255, 255, 255, 0.94);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
            backdrop-filter: saturate(180%) blur(20px);
  }
  .tabbar-item {
    min-height: 50px;
    padding: 5px 2px 4px;
    display: grid;
    justify-items: center;
    align-content: center;
    gap: 3px;
    border: 0;
    border-radius: var(--r-md);
    background: none;
    color: var(--text-muted);
    font-family: var(--font-text);
    font-size: 10px;
    font-weight: var(--w-title);
    line-height: 1.2;
    letter-spacing: 0;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .tabbar-icon {
    width: 44px;
    height: 26px;
    display: grid;
    place-items: center;
    border-radius: var(--r-pill);
    transition: background 140ms ease;
  }
  .tabbar-icon svg { width: 21px; height: 21px; }
  .tabbar-item.active,
  .tabbar-item[aria-expanded="true"] { color: var(--ink); }
  .tabbar-item.active .tabbar-icon,
  .tabbar-item[aria-expanded="true"] .tabbar-icon { background: var(--canvas-soft); }
  body.nav-sheet-open .tabbar { z-index: 50; }

  /* The sheet stands on the bar rather than under it. */
  .sidebar { bottom: calc(72px + max(var(--app-content-safe-bottom), env(safe-area-inset-bottom))); }

  /* The bar carries navigation now, so the topbar keeps only the
     title: two 44px targets in the corner furthest from the thumb
     were the duplicate. */
  .topbar { grid-template-columns: minmax(0, 1fr); }
  .topbar-search { display: none; }

  /* The topbar states the section; a page that repeats it in an
     <h1> is spending 60px to say it twice. The heading stays in the
     document for screen readers and outline order. */
  .page-title {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .page-head { margin-bottom: 16px; gap: 12px; }
  .page-head:empty { display: none; }

  /* The footer band is a desktop end-stop; on a phone it is one more
     screen of chrome between the last row and the tab bar. */
  .app-footer { display: none; }
}

@media (max-width: 640px) {
  h1 { font-size: 26px; }
  .card { padding: 20px; }
  .grid { gap: 12px; }
  .chart { height: 230px; }
  .search-hero { gap: 16px; }

  /* Wide tables scroll inside their own container rather than
     pushing the page sideways. */
  table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  th, td { min-width: 96px; white-space: nowrap; }
  td:first-child, th:first-child { min-width: 136px; }
  .toolbar > input,
  .toolbar > select,
  .toolbar > .input { max-width: none; }

  /* …unless every row maps cleanly onto its header, in which case
     miniapp.js relabels the cells and the table becomes a stack of
     record cards. */
  table.mobile-cards-table,
  table.mobile-cards-table.card {
    display: block;
    max-width: none;
    padding: 0;
    overflow: visible;
    border: 0;
    border-radius: 0;
    background: transparent;
  }
  .mobile-cards-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .mobile-cards-table tbody { display: grid; gap: 12px; }
  .mobile-cards-table tbody tr {
    display: grid;
    padding: 6px 20px;
    overflow: hidden;
    border: 1px solid var(--hairline-soft);
    border-radius: var(--r-card);
    background: var(--canvas);
  }
  .card > .mobile-cards-table tbody tr { background: var(--canvas-soft); border-color: transparent; }
  .mobile-cards-table tbody tr:hover { background: var(--canvas-soft); }
  .mobile-cards-table td,
  .mobile-cards-table td:first-child {
    min-width: 0;
    padding: 12px 0;
    display: grid;
    grid-template-columns: minmax(88px, 0.7fr) minmax(0, 1.3fr);
    gap: 12px;
    align-items: center;
    border-top: none;
    border-bottom: 1px solid var(--hairline-soft);
    color: var(--ink);
    text-align: right;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .mobile-cards-table td::before {
    content: attr(data-label);
    color: var(--text-muted);
    font-size: 12px;
    font-weight: var(--w-title);
    line-height: 1.33;
    letter-spacing: 0;
    text-align: left;
    text-transform: none;
  }
  /* The value column is a grid track: inline chrome would stretch
     across it, so pills and code hug the right edge instead. */
  .mobile-cards-table td > .pill,
  .mobile-cards-table td > .badge-accent,
  .mobile-cards-table td > code { justify-self: end; }
  .mobile-cards-table td:last-child { border-bottom: 0; }
  .mobile-cards-table td.mobile-action-cell { grid-template-columns: 1fr; padding-top: 14px; }
  .mobile-cards-table td.mobile-action-cell::before { display: none; }
  .mobile-cards-table td.mobile-action-cell .btn,
  .mobile-cards-table td.mobile-action-cell > a,
  .mobile-cards-table td.mobile-action-cell > form,
  .mobile-cards-table td.mobile-action-cell > button { width: 100%; min-height: 44px; }
  .mobile-cards-table td code { max-width: 100%; overflow-wrap: anywhere; white-space: normal; }
}

@media (max-width: 560px) {
  .topbar { gap: 8px; }
  .dashboard-heading { align-items: end; gap: 12px; }
  .dashboard-heading h1 { font-size: 28px; }
  .dashboard-heading p { display: none; }
  .dashboard-period { flex-basis: 132px; }
  .dashboard-period label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }
  .dashboard-kpi { min-height: 116px; padding: 18px; }
  .app-footer { flex-direction: column; align-items: flex-start; gap: 12px; }
}

/* The dashboard is a menu, not a workspace: on a wide screen it
   drops the sidebar and centres itself on the canvas the way the
   system's own pages do. */
@media (min-width: 901px) {
  body[data-active-section="dashboard"] .app-shell { display: block; }
  body[data-active-section="dashboard"] .sidebar,
  body[data-active-section="dashboard"] .sidebar-backdrop { display: none; }
  body[data-active-section="dashboard"] .workspace {
    width: min(1180px, calc(100% - 48px));
    min-height: 100vh;
    margin: 0 auto;
  }
  body[data-active-section="dashboard"] .workspace main { width: 100%; }
}

/* The search page owns the query: the topbar duplicate would be a
   second field for the same job. */
body[data-active-section="owner_search"] .topbar-search { display: none; }

@media (prefers-reduced-motion: reduce) {
  .search-spinner,
  .telegram-auth-loader span { animation: none; }
  .sidebar,
  .sidebar-backdrop,
  .search-customer-card,
  .search-result-card,
  .advanced > summary::after { transition: none; }
}

@media print {
  .sidebar, .topbar, .app-footer, .skip-link { display: none; }
  .workspace main { padding: 0; }
  .card, table { border-color: var(--hairline); }
}
