/* =============================================================================
 * theme.css — the design system for the InfinityPro TV sales console.
 *
 * ONE place defines colour, type, density, radius and elevation. Everything
 * else in the app (Tailwind utilities included — see the `tailwind.config`
 * block in app.html, which maps utility colour names onto these same tokens)
 * reads from here. If a value is not in this file, it should not be in the app.
 *
 * The idea the whole thing hangs off: in this business every lead is a running
 * clock — a trial that expires, a payment promised for 4pm, a subscription
 * that ends in twelve days. So **colour encodes time pressure, not stage.**
 * Stage is carried by position and label; red/amber/green mean late/due/won and
 * nothing else. That is why the board columns are not seven different colours.
 *
 * Colours are stored as bare RGB triplets so Tailwind's slash-opacity syntax
 * (bg-surface/80) keeps working; `--x` is the ready-to-use rgb() form.
 * ========================================================================== */

:root {
  /* --- neutral ramp: "ash", a cool graphite at hue ~205 ---------------------
   * Deliberately not Tailwind slate (which leans lavender) and deliberately not
   * a warm paper cream. Reads as pencil on newsprint under office light. */
  --rgb-ash-0:   255 255 255;
  --rgb-ash-25:  250 251 251;
  --rgb-ash-50:  243 245 246;
  --rgb-ash-100: 232 236 238;
  --rgb-ash-200: 213 219 222;
  --rgb-ash-300: 184 193 198;
  --rgb-ash-400: 138 148 155;   /* 3.09:1 on white — the UI-border floor */
  --rgb-ash-450: 154 164 170;   /* the dark theme's quiet text tone           */
  --rgb-ash-500: 97 108 116;    /* 4.92:1 on the canvas, 4.52:1 in a well    */
  --rgb-ash-600: 78 88 95;      /* 7.28:1                                    */
  --rgb-ash-700: 59 68 74;
  --rgb-ash-800: 43 50 55;
  --rgb-ash-900: 29 35 39;
  --rgb-ash-950: 18 23 26;

  /* --- accent: "signal", a petrol blue ------------------------------------
   * Allowed in exactly four places: the primary button, the current nav item,
   * the focus ring, and the active state of a control (tab, toggle, selected
   * row rail). Never on headings, never on icons that sit next to a label,
   * never as decoration. */
  --rgb-signal-50:  232 241 246;
  --rgb-signal-100: 205 226 236;
  --rgb-signal-200: 159 199 218;
  --rgb-signal-300: 107 167 194;   /* dark-mode accent text: 6.8:1 on ash-950 */
  --rgb-signal-400: 58 133 166;
  --rgb-signal-500: 29 110 143;
  --rgb-signal-600: 20 92 121;     /* primary: 7.4:1 on white, 5.5:1 for white-on */
  --rgb-signal-700: 15 74 98;
  --rgb-signal-800: 11 58 77;

  /* --- semantic: time pressure, and only that -----------------------------
   * late  — past due: an overdue follow-up, an expired trial, a lost lead
   * due   — inside the action window: due today, trial expiring, balance owed
   * won   — money in: paid, live subscription
   * There is no fourth. A stage that is none of these is neutral. */
  /* late and due sit ~1.2 apart in deuteranopia, and no hue along the red-to-
   * olive axis separates them: that axis is exactly what deuteranopes collapse.
   * Lightness is closed off too — both have to clear 4.5:1 as text on white.
   * They stay as they are because they are status colours, and every place they
   * appear the word carries the meaning ("56d late", "in 3h") with the colour
   * only reinforcing it. Do not use this pair to distinguish anything unlabelled. */
  --rgb-late: 178 58 46;
  --rgb-late-soft: 251 236 234;
  --rgb-late-line: 240 205 200;
  --rgb-due: 143 92 14;
  --rgb-due-soft: 251 242 227;
  --rgb-due-line: 238 217 178;
  --rgb-won: 44 115 85;
  --rgb-won-soft: 232 243 237;
  --rgb-won-line: 191 219 205;

  /* ready-to-use forms ----------------------------------------------------- */
  --ash-0: rgb(var(--rgb-ash-0));      --ash-25: rgb(var(--rgb-ash-25));
  --ash-50: rgb(var(--rgb-ash-50));    --ash-100: rgb(var(--rgb-ash-100));
  --ash-200: rgb(var(--rgb-ash-200));  --ash-300: rgb(var(--rgb-ash-300));
  --ash-400: rgb(var(--rgb-ash-400));  --ash-450: rgb(var(--rgb-ash-450));
  --ash-500: rgb(var(--rgb-ash-500));
  --ash-600: rgb(var(--rgb-ash-600));  --ash-700: rgb(var(--rgb-ash-700));
  --ash-800: rgb(var(--rgb-ash-800));  --ash-900: rgb(var(--rgb-ash-900));
  --ash-950: rgb(var(--rgb-ash-950));

  /* --- roles (what the app actually references) --------------------------- */
  --bg-app:      rgb(var(--rgb-ash-50));
  --bg-surface:  rgb(var(--rgb-ash-0));
  --bg-sunken:   rgb(var(--rgb-ash-100));
  --bg-hover:    rgb(var(--rgb-ash-50));
  --bg-active:   rgb(var(--rgb-signal-50));
  --fg:          rgb(var(--rgb-ash-900));
  --fg-2:        rgb(var(--rgb-ash-600));
  --fg-3:        rgb(var(--rgb-ash-500));   /* the quietest tone allowed to carry words */
  --fg-4:        rgb(var(--rgb-ash-400));   /* borders, placeholder marks, icon fills — NOT text */
  --line:        rgb(var(--rgb-ash-200));
  --line-soft:   rgb(var(--rgb-ash-100));
  --line-strong: rgb(var(--rgb-ash-400));
  --accent:      rgb(var(--rgb-signal-600));
  --accent-hi:   rgb(var(--rgb-signal-700));
  --accent-fg:   #fff;
  --accent-soft: rgb(var(--rgb-signal-50));
  --accent-line: rgb(var(--rgb-signal-200));
  --late:        rgb(var(--rgb-late));
  --late-soft:   rgb(var(--rgb-late-soft));
  --late-line:   rgb(var(--rgb-late-line));
  --due:         rgb(var(--rgb-due));
  --due-soft:    rgb(var(--rgb-due-soft));
  --due-line:    rgb(var(--rgb-due-line));
  --won:         rgb(var(--rgb-won));
  --won-soft:    rgb(var(--rgb-won-soft));
  --won-line:    rgb(var(--rgb-won-line));

  /* --- chart fills ---------------------------------------------------------
   * The UI's accent and semantic tones are picked to be readable as *text*,
   * which makes them too low in chroma to work as large filled marks — a bar
   * painted in them reads grey. These two are the same hues stepped up until
   * they clear the chroma floor, and they exist only inside a plot.
   *
   * There are two because there are two single-series charts, not because
   * anything is categorical: money over time, and the funnel. They are never
   * used side by side to distinguish series — validated as a pair they fail the
   * normal-vision separation floor, and correctly so.
   *
   *   money — every bar is revenue, so it wears the colour money already has
   *   flow  — stages of one measure narrowing; length carries the magnitude,
   *           the hue only says "this is the funnel"
   */
  --chart-money: #2f8659;
  --chart-flow:  #1272a0;

  /* --- type ---------------------------------------------------------------
   * Two families, unmistakably different in role:
   *   Sans  — everything a person wrote or reads as language.
   *   Mono  — every number a person compares: money, phone, dates, counts,
   *           durations, IDs. Comparison is the whole job of this app, so the
   *           numbers get a face that lines up in columns by construction.
   * IBM Plex carries Latin, Arabic and Mono in one superfamily, which matters:
   * half these customers' names are Arabic. */
  --font-sans: "IBM Plex Sans", "IBM Plex Sans Arabic", "Segoe UI", Tahoma, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* six sizes, all used. Tracking tightens as size grows. */
  --t-micro: 11px;   --lh-micro: 14px;   --tr-micro: .01em;
  --t-meta:  12px;   --lh-meta:  16px;   --tr-meta:  .005em;
  --t-body:  13px;   --lh-body:  18px;   --tr-body:  0;
  --t-lead:  15px;   --lh-lead:  20px;   --tr-lead:  -.006em;
  --t-title: 19px;   --lh-title: 24px;   --tr-title: -.015em;
  --t-hero:  28px;   --lh-hero:  30px;   --tr-hero:  -.022em;

  /* --- density ------------------------------------------------------------
   * Base unit 4px, held everywhere. Row height 36px: the shortest a 13px name
   * over a 12px mono phone number can sit without the two touching, which puts
   * ~19 leads above the fold on a 13" laptop. Three paddings exist in the whole
   * application, and two radii. */
  --u: 4px;
  --pad-tight: 8px;    /* inside a control, a cell, a chip        */
  --pad: 12px;         /* inside a toolbar, a list item, a header */
  --pad-panel: 20px;   /* inside a panel, a modal, the page gutter */
  --row: 36px;
  --row-lg: 44px;      /* the queue call-sheet, which is touched not scanned */
  --r-ctl: 3px;        /* buttons, inputs, chips, cells           */
  --r-box: 6px;        /* panels, modals, drawer, popovers        */

  /* --- elevation ----------------------------------------------------------
   * Hairlines separate; shadow is only for things that genuinely float.
   * One token. */
  --shadow-overlay: 0 10px 28px -8px rgb(var(--rgb-ash-950) / .34),
                    0 2px 6px -2px rgb(var(--rgb-ash-950) / .16);
  /* Surfaces are separated by a hairline here, so there is nothing under them.
   * The token exists because the Tailwind bridge reads it for shadow-sm/md, and
   * because the Classic skin does put a shadow there. */
  --shadow-panel: none;

  /* --- motion ------------------------------------------------------------- */
  --ease: cubic-bezier(.2, .7, .35, 1);
  --dur: 140ms;

  --focus: rgb(var(--rgb-signal-500));
  color-scheme: light;
}

/* --- dark: the same ramp read from the other end ---------------------------
 * Not an inversion — the surfaces separate by a step of the ramp, the accent
 * and the semantics move up to their light-on-dark tones so every one of them
 * still clears 4.5:1. */
.dark {
  --bg-app:      rgb(var(--rgb-ash-950));
  --bg-surface:  rgb(var(--rgb-ash-900));
  --bg-sunken:   rgb(var(--rgb-ash-800));
  --bg-hover:    rgb(var(--rgb-ash-800));
  --bg-active:   rgb(var(--rgb-signal-800) / .55);
  --fg:          rgb(var(--rgb-ash-50));
  --fg-2:        rgb(var(--rgb-ash-300));
  --fg-3:        rgb(var(--rgb-ash-450));
  --fg-4:        rgb(var(--rgb-ash-400));
  --line:        rgb(var(--rgb-ash-800));
  --line-soft:   rgb(var(--rgb-ash-800));
  --line-strong: rgb(var(--rgb-ash-600));
  --accent:      rgb(var(--rgb-signal-300));
  --accent-hi:   rgb(var(--rgb-signal-200));
  --accent-fg:   rgb(var(--rgb-ash-950));
  --accent-soft: rgb(var(--rgb-signal-800) / .4);
  --accent-line: rgb(var(--rgb-signal-700));
  --late:        #e8887c;
  --late-soft:   rgb(178 58 46 / .17);
  --late-line:   rgb(178 58 46 / .42);
  --due:         #e0ae5a;
  --due-soft:    rgb(154 100 16 / .2);
  --due-line:    rgb(154 100 16 / .5);
  --won:         #6dbf9a;
  --won-soft:    rgb(44 115 85 / .2);
  --won-line:    rgb(44 115 85 / .48);
  /* Stepped for the dark surface rather than flipped: the light values sit
   * outside the band the dark chart surface allows (L 0.48-0.67). */
  --chart-money: #4aa87c;
  --chart-flow:  #3f9fce;
  --focus:       rgb(var(--rgb-signal-300));
  --shadow-overlay: 0 10px 28px -8px rgb(0 0 0 / .6), 0 2px 6px -2px rgb(0 0 0 / .4);
  color-scheme: dark;
}

/* =============================================================================
 * Base
 * ========================================================================== */

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-sans);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  letter-spacing: var(--tr-body);
  background: var(--bg-app);
  color: var(--fg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: "cv05" 1;   /* Plex's single-storey-tailed l — reads faster at 11-13px */
}

/* Numbers are data. Every one of them lines up. */
.num, input[type="number"], td .num, kbd {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "zero" 1;   /* slashed zero: 0 vs O in an M3U id */
  letter-spacing: -.01em;
}
/* Sans that still has to align in a column (a name cell holding a count). */
.tnum { font-variant-numeric: tabular-nums lining-nums; }

/* =============================================================================
 * Focus — one ring, everywhere, never removed.
 * Two-tone so it survives on both the app canvas and a coloured button.
 * ========================================================================== */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible,
.focusable:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-radius: var(--r-ctl);
}
/* Rows and cards get the ring inset so it can't be clipped by the scroller. */
.focus-inset:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }

/* =============================================================================
 * Type roles
 * ========================================================================== */
.t-micro { font-size: var(--t-micro); line-height: var(--lh-micro); letter-spacing: var(--tr-micro); }
.t-meta  { font-size: var(--t-meta);  line-height: var(--lh-meta);  letter-spacing: var(--tr-meta); }
.t-body  { font-size: var(--t-body);  line-height: var(--lh-body); }
.t-lead  { font-size: var(--t-lead);  line-height: var(--lh-lead);  letter-spacing: var(--tr-lead); }
.t-title { font-size: var(--t-title); line-height: var(--lh-title); letter-spacing: var(--tr-title); font-weight: 600; }
.t-hero  { font-size: var(--t-hero);  line-height: var(--lh-hero);  letter-spacing: var(--tr-hero); font-weight: 600; }

/* Field label / column head. Sentence case, never tracked-out caps. */
.label {
  font-size: var(--t-micro); line-height: var(--lh-micro);
  letter-spacing: var(--tr-micro); font-weight: 600; color: var(--fg-3);
}

/* Truncation rules, stated once and applied by name:
 *   .clip     — one line, ellipsis. Company and customer names, campaigns.
 *   .clip-2   — two lines then ellipsis. Note previews only.
 *   .clip-mid — long ids/emails keep their tail (the part that disambiguates)
 *               by scrolling rather than truncating; the row never grows. */
.clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clip-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.clip-mid { overflow-x: auto; white-space: nowrap; scrollbar-width: none; }
.clip-mid::-webkit-scrollbar { display: none; }

/* =============================================================================
 * Surfaces — hairlines, not shadows. No nesting: a panel never contains
 * another panel.
 * ========================================================================== */
.panel {
  background: var(--bg-surface);
  border: 1px solid var(--line);
  border-radius: var(--r-box);
  /* A panel must never refuse to shrink. As a grid or flex child its default
   * min-width:auto is its CONTENT's minimum, so one wide thing inside — a chart
   * with a per-bucket floor, a table with a min-width row — stopped the panel
   * shrinking and pushed it past the viewport instead of scrolling inside it.
   * Measured at 390px: the trend panel came out 1165px and dragged the funnel
   * beside it out to 1165px too. min-width:0 is what lets the scroll container
   * inside actually scroll. */
  min-width: 0;
}
.panel-hd {
  display: flex; align-items: center; gap: var(--pad-tight);
  height: 40px; padding: 0 var(--pad);
  border-bottom: 1px solid var(--line);
}
.panel-hd h2, .panel-hd h3 {
  font-size: var(--t-body); font-weight: 600; letter-spacing: 0; color: var(--fg);
}
.panel-bd { padding: var(--pad-panel); }
.panel-bd-flush { padding: 0; }

/* A hairline that encodes real separation. */
.rule { border: 0; border-top: 1px solid var(--line); margin: 0; }

/* =============================================================================
 * Controls
 * ========================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 30px; padding: 0 10px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-ctl);
  background: var(--bg-surface); color: var(--fg);
  font-family: inherit; font-size: var(--t-body); font-weight: 500; line-height: 1;
  cursor: pointer; white-space: nowrap;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.btn:hover { background: var(--bg-hover); }
.btn:active { background: var(--bg-sunken); }
.btn[disabled], .btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-lg { height: 34px; padding: 0 14px; }
.btn-sm { height: 26px; padding: 0 8px; font-size: var(--t-meta); }
.btn-icon { width: 30px; padding: 0; }
.btn-icon.btn-sm { width: 26px; }

/* The primary action. One per surface. */
.btn-primary {
  background: var(--accent); border-color: var(--accent); color: var(--accent-fg); font-weight: 600;
}
.btn-primary:hover { background: var(--accent-hi); border-color: var(--accent-hi); }
.btn-primary:active { background: var(--accent-hi); }

/* Quiet: toolbar actions that are not the primary one. */
.btn-ghost { border-color: transparent; background: transparent; color: var(--fg-2); }
.btn-ghost:hover { background: var(--bg-hover); color: var(--fg); }

/* Destructive. Outline until hovered — it should take a deliberate move. */
.btn-danger { color: var(--late); border-color: var(--late-line); background: var(--bg-surface); }
.btn-danger:hover { background: var(--late-soft); border-color: var(--late); }

.field {
  display: block; width: 100%; height: 30px;
  padding: 0 var(--pad-tight);
  border: 1px solid var(--line-strong); border-radius: var(--r-ctl);
  background: var(--bg-surface); color: var(--fg);
  font-family: inherit; font-size: var(--t-body); line-height: 28px;
  transition: border-color var(--dur) var(--ease);
}
textarea.field { height: auto; padding: 6px var(--pad-tight); line-height: var(--lh-body); resize: vertical; }
select.field { padding-inline-end: 22px; }
.field::placeholder { color: var(--fg-4); }
.field:hover { border-color: var(--fg-3); }
.field:focus { outline: 2px solid var(--focus); outline-offset: -1px; border-color: var(--focus); }
.field-lg { height: 34px; line-height: 32px; }
.field[aria-invalid="true"] { border-color: var(--late); }

/* Chip: a filter or a tag. Removable ones carry an ×. */
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; padding: 0 7px;
  border: 1px solid var(--line); border-radius: var(--r-ctl);
  background: var(--bg-surface); color: var(--fg-2);
  font-size: var(--t-micro); line-height: 1; font-weight: 500; white-space: nowrap;
}
.chip-on { border-color: var(--accent-line); background: var(--accent-soft); color: var(--accent); font-weight: 600; }

/* Badge: state that changes. Never a decoration, never on a static field. */
.badge {
  display: inline-flex; align-items: center; gap: 4px;
  height: 18px; padding: 0 6px; border-radius: var(--r-ctl);
  font-size: var(--t-micro); line-height: 1; font-weight: 600; white-space: nowrap;
  background: var(--bg-sunken); color: var(--fg-2);
}
.badge-late { background: var(--late-soft); color: var(--late); }
.badge-due  { background: var(--due-soft);  color: var(--due); }
.badge-won  { background: var(--won-soft);  color: var(--won); }
.badge-count { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* A count that sits next to a label — mono, so 7 and 117 don't shuffle it. */
.count { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--fg-3); }

/* Segmented control: view switches, ranges, the AM/PM pair.
 *
 * A seven-option range switch does not fit a phone. It scrolls sideways rather
 * than wrapping, because a wrapped segmented control reads as two controls —
 * and the labels never wrap, which is what used to clip "This month" against
 * the fixed row height. `flex: none` on the buttons keeps them at their natural
 * width inside the scroller instead of being squeezed to fit. */
.seg {
  /* inline-flex, so a segmented control is only as wide as its options — the
   * full-width case is opt-in via .seg-fill, not the default. */
  display: inline-flex; max-width: 100%; vertical-align: middle;
  border: 1px solid var(--line-strong); border-radius: var(--r-ctl);
  overflow-x: auto; overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.seg::-webkit-scrollbar { display: none; }
.seg > button {
  flex: none;
  height: 28px; padding: 0 10px; border: 0; border-inline-start: 1px solid var(--line);
  background: var(--bg-surface); color: var(--fg-2);
  font-family: inherit; font-size: var(--t-meta); font-weight: 500; cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.seg > button:first-child { border-inline-start: 0; }
/* Full-width variant, for a short set of options on a phone: the segments share
 * the row evenly so each is a thumb-sized target, and take their natural width
 * again from `sm` up. It lives here rather than as a utility because
 * `.seg > button`'s own `flex: none` outranks a single-class utility. */
.seg-fill > button { flex: 1 1 0; min-width: 0; }
@media (min-width: 640px) { .seg-fill > button { flex: none; } }
.seg > button:hover { background: var(--bg-hover); color: var(--fg); }
.seg > button[aria-pressed="true"], .seg > button.is-on {
  background: var(--accent); color: var(--accent-fg); font-weight: 600;
}
.seg > button:focus-visible { outline-offset: -2px; }

/* =============================================================================
 * Data table — the surface the whole job happens on.
 * ========================================================================== */
.tbl { width: 100%; border-collapse: separate; border-spacing: 0; }
.tbl thead th {
  position: sticky; top: 0; z-index: 1;
  height: 28px; padding: 0 var(--pad-tight);
  background: var(--bg-surface);
  border-bottom: 1px solid var(--line);
  font-size: var(--t-micro); line-height: var(--lh-micro); letter-spacing: var(--tr-micro);
  font-weight: 600; color: var(--fg-3); text-align: start; white-space: nowrap;
}
.tbl thead th.is-sorted { color: var(--fg); }
.tbl tbody td {
  height: var(--row); padding: 0 var(--pad-tight);
  border-bottom: 1px solid var(--line-soft);
  vertical-align: middle;
}
.tbl tbody tr { transition: background-color var(--dur) var(--ease); }
/* Hover is a value shift, not a glow. */
.tbl tbody tr:hover { background: var(--bg-hover); }
.tbl tbody tr[aria-selected="true"] { background: var(--bg-active); }
/* Keyboard cursor: a rail on the leading edge, so it is distinguishable from
 * hover and from selection at a glance. */
.tbl tbody tr.is-cursor { background: var(--bg-hover); box-shadow: inset 2px 0 0 0 var(--accent); }
.tbl tbody tr.is-cursor:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
/* Numeric columns align right; the mono face is for the data, not the heading —
 * a column head is a word, and words are set in the sans. */
.tbl td.num-cell, .tbl th.num-cell { text-align: end; }
.tbl td.num-cell { font-family: var(--font-mono); font-variant-numeric: tabular-nums lining-nums; }
.tbl th.num-cell > button { justify-content: flex-end; }
.tbl .col-tight { width: 1%; white-space: nowrap; }

/* =============================================================================
 * Nav
 * ========================================================================== */
.nav-item {
  display: flex; align-items: center; gap: 10px;
  height: 30px; padding: 0 var(--pad-tight);
  border-radius: var(--r-ctl);
  color: var(--fg-2); font-size: var(--t-body); font-weight: 500;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.nav-item:hover { background: var(--bg-hover); color: var(--fg); }
.nav-item.active { background: var(--bg-active); color: var(--accent); font-weight: 600; }
.nav-item.active svg { color: var(--accent); }
.nav-item svg { color: var(--fg-4); flex: none; }
.nav-item:hover svg { color: var(--fg-3); }
.nav-sec {
  padding: 0 var(--pad-tight); margin: 14px 0 4px;
  font-size: var(--t-micro); line-height: var(--lh-micro); font-weight: 600; color: var(--fg-3);
}

/* =============================================================================
 * Overlays — the only place shadow is allowed.
 * ========================================================================== */
.overlay { background: rgb(var(--rgb-ash-950) / .38); }
.floating {
  background: var(--bg-surface); border: 1px solid var(--line);
  border-radius: var(--r-box); box-shadow: var(--shadow-overlay);
}

/* =============================================================================
 * Loading — a skeleton the exact shape of the thing that is coming, so the
 * layout does not move when it arrives.
 * ========================================================================== */
.skel { background: var(--bg-sunken); border-radius: 2px; height: 9px; display: block; }
.skel-pulse { animation: skel 1.1s var(--ease) infinite; }
@keyframes skel { 0%, 100% { opacity: 1 } 50% { opacity: .45 } }

/* =============================================================================
 * The clock — this app's one loud idea. Everywhere a time is shown, its
 * distance from now is the thing you read first.
 * ========================================================================== */
.due-late { color: var(--late); font-weight: 600; }
.due-now  { color: var(--due);  font-weight: 600; }
.due-cool { color: var(--fg-3); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}

/* Neutral is the badge's own look; the class exists so the markup can say
 * which tone it means rather than relying on the absence of one. */
.badge-neutral { }

/* Keyboard hints, shown next to the list they drive. */
kbd {
  display: inline-block; min-width: 16px; padding: 0 4px;
  border: 1px solid var(--line); border-radius: 3px;
  background: var(--bg-surface); color: var(--fg-3);
  font-size: 10px; line-height: 15px; text-align: center;
}

/* =============================================================================
 * Figure strip — a run of readings divided by hairlines, inside one panel.
 * Deliberately not a row of cards: a card implies each number is a thing you
 * can open, and these are readings off a single instrument.
 * ========================================================================== */
/* The dividers are drawn by the cells, so a half-filled last row used to leave
 * the rule between rows stopping halfway across — the empty cells had no border
 * to contribute. Rather than chase that with pseudo-elements, the column count
 * is chosen per strip to divide its number of readings exactly (see the
 * grid-cols utilities on each .figs in the markup), so a partial row never
 * happens. The two negative margins pull the first column's and first row's
 * rules onto the panel's own border instead of doubling it, which is what lets
 * every cell keep an unconditional border. */
.figs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: -1px;
  margin-inline-start: -1px;
  overflow: hidden;
}
.figs > * {
  padding: 10px var(--pad);
  border-inline-start: 1px solid var(--line);
  border-top: 1px solid var(--line);
  text-align: start;
  min-width: 0;
}
.fig-l {
  font-size: var(--t-micro); line-height: var(--lh-micro); font-weight: 600; color: var(--fg-3);
  /* A wrapped label would make one cell taller than its neighbours and break
     the row rule's alignment. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fig-v {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums lining-nums;
  font-size: var(--t-title); line-height: 26px; letter-spacing: -.02em; font-weight: 600;
  margin-top: 2px; color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
a.figs-item:hover, button.figs-item:hover { background: var(--bg-hover); }

/* Horizontal proportion bar — pipeline shares, target progress. One height,
 * one radius, neutral unless the row is a state you act on. */
.meter { height: 6px; background: var(--bg-sunken); border-radius: 2px; overflow: hidden; }
.meter > i { display: block; height: 100%; background: var(--fg-4); border-radius: 2px; }
.meter-accent > i { background: var(--accent); }
.meter-won > i { background: var(--won); }

/* =============================================================================
 * Record sections — the lead drawer and the settings pages.
 * Sections are separated by a hairline and a label, never by nesting a box
 * inside a box. Nothing in this app is a card inside a card.
 * ========================================================================== */
/* A drawer section is a box, not a band. Flat sections separated by a hairline
 * read as one long page and give the eye nothing to stop on; the lead record is
 * scanned for one fact at a time — the money, the line, the next follow-up — so
 * each section is a card on the sunken drawer ground, the same surface/line/
 * radius trio as .panel. Same tokens, no new colour. */
.sec {
  padding: 16px var(--pad);
  /* Matched to the drawer this replaced. That design's generic section was
   *     bg-slate-50/70 + border-slate-200 + rounded-xl + shadow-xs
   * — a LIGHT tint sitting on a white drawer, with a hairline and just enough
   * shadow to lift it. --bg-app is ash-50 (243 245 246), which is slate-50 to
   * within a shade, so the pairing comes back as tokens: tinted box on the
   * surface ground. --bg-sunken (232) was heavier than the original.
   *
   * --sec-bg / --sec-line / --sec-fg are the tone hooks below. Unset, a section
   * is the neutral box; a section that declares a tone re-points all three at
   * once and everything inside it — the heading, the tile hairlines, the
   * timeline spine — follows without a selector per part. */
  background: var(--sec-bg, var(--bg-app));
  border: 1px solid var(--sec-line, var(--line));
  border-radius: var(--r-box);
  box-shadow: 0 1px 2px 0 rgb(var(--rgb-ash-950) / .04);
}
.sec + .sec { margin-top: var(--pad-tight); }

/* Tone: colour on the drawer, which is the thing the flat redesign took out.
 *
 * The drawer before the redesign did not tint every box the same, and the three
 * grounds it used meant something:
 *
 *   the record and its history   bg-amber-50/40  + border-amber-300
 *   the money                    bg-emerald-50/50 + border-emerald-200
 *   what you act with            bg-slate-50/70   + border-slate-200, indigo icon
 *
 * Those were literal Tailwind classes. Here they are the due / won / accent
 * tokens, which are the same three hues said once — so Classic renders the
 * original amber-50, emerald-50 and indigo-50 values, and the console skin
 * renders its own, off one set of rules.
 *
 * Four tinted boxes out of ten, not ten. A ground that every section shares is
 * a ground, not a signal; the sections you act *with* (Tags, Notes, the
 * template picker, Remove) stay neutral on purpose, and the notices inside a
 * section keep their own state colour on top.
 *
 * A tinted box needs white tiles or the tint reads as dirt — that was the other
 * half of the original, bg-white/80 sitting inside bg-amber-50/40. `.dl > div`
 * already paints --bg-surface, so it holds here with no branch; only its
 * hairline has to pick the tone up. */
.sec[data-tone="due"]    { --sec-bg: var(--due-soft);    --sec-line: var(--due-line);    --sec-fg: var(--due); }
.sec[data-tone="won"]    { --sec-bg: var(--won-soft);    --sec-line: var(--won-line);    --sec-fg: var(--won); }
.sec[data-tone="accent"] { --sec-bg: var(--accent-soft); --sec-line: var(--accent-line); --sec-fg: var(--accent); }
/* "bare" is the opposite: a spacing shell, no box. The notices inside it are
 * boxes in their own right and carry their own state colour — they stood alone
 * in the old drawer — so wrapping them in a second one is a box inside a box. */
.sec[data-tone="bare"] { padding: 0; background: none; border: 0; box-shadow: none; }
.sec-h { display: flex; align-items: center; gap: var(--pad-tight); margin-bottom: 10px; }
.sec-h h3 {
  font-size: var(--t-micro); line-height: var(--lh-micro); letter-spacing: var(--tr-micro);
  font-weight: 600; color: var(--fg-3);
}
/* The heading is the one word in a tinted section allowed to carry the hue.
 * All three tones are the text-legible tokens, so they clear 4.5:1 on their own
 * soft ground — that is what those values were picked for. */
.sec[data-tone] .sec-h h3 { color: var(--sec-fg); }

/* The mark beside a section label.
 *
 * The tokens at the top of this file say the accent is never allowed on an icon
 * that sits next to a label. This is the one exception, and it is deliberate:
 * the drawer before the redesign put a small coloured glyph on every section
 * heading — indigo-500 on the neutral sections, amber-600 on the amber ones —
 * and that mark is most of how the drawer read as a set of distinct places
 * rather than one scrolling page. Nowhere else in the app gets this; the rule
 * still holds for the lists, the board and the analytics pages.
 *
 * A toned section's mark takes the tone, a neutral one takes the accent, which
 * is the same pairing the old drawer used. 14px, because the label it sits
 * beside is 11px. */
.sec-h h3 { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.sec-i { width: 14px; height: 14px; flex: none; color: var(--sec-fg, var(--accent)); }

/* Analytics rows are a grid, not a <table>.
 *
 * Two cards sitting side by side have to line their columns up with each other,
 * and independent table layout will never do that: each <table> sizes to its
 * own content, so "By campaign" with one row and "By channel" with two came out
 * a few pixels apart on every column. A shared column template makes the
 * alignment a property of the design rather than a coincidence of the data.
 *
 * Each row is its own grid over the same template — rather than one grid with
 * display:contents — so a row can carry its own hover and border.
 *
 * On a narrow screen the row keeps its min-width and the card scrolls sideways.
 * Squeezing five numeric columns into 320px loses the alignment this exists to
 * create, and dropping columns loses data the page is there to show. */
.gt { --gt-cols: minmax(0, 1fr) repeat(4, 4.75rem); --gt-min: 26rem; overflow-x: auto; }
.gt-row {
  display: grid;
  grid-template-columns: var(--gt-cols);
  align-items: center;
  min-width: var(--gt-min);
}
.gt-row > * { padding: 9px var(--pad-tight); min-width: 0; }
.gt-row > :first-child { padding-inline-start: var(--pad); }
.gt-row > :last-child  { padding-inline-end: var(--pad); }
.gt-row + .gt-row { border-top: 1px solid var(--line-soft); }
.gt-head {
  font-size: var(--t-micro); line-height: var(--lh-micro); letter-spacing: var(--tr-micro);
  font-weight: 600; color: var(--fg-3);
  border-bottom: 1px solid var(--line);
}
.gt-head + .gt-row { border-top: 0; }
.gt-body .gt-row:hover { background: var(--bg-hover); }
.gt-num { text-align: end; font-variant-numeric: tabular-nums; }
.gt-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gt-empty { padding: 22px var(--pad); text-align: center; color: var(--fg-3); font-size: var(--t-body); }

/* Definition list: label above value, two up on a wide drawer.
 *
 * Each pair is a tile on the section's tint. This is the half that was missing:
 * the old drawer read as structured not because its sections were tinted, but
 * because tinted sections held WHITE tiles — bg-slate-50/70 outside,
 * bg-white/80 + border + rounded-lg inside. A tint alone is a 12-point step
 * that you have to look for; tint against surface, with a hairline between, is
 * the pairing that actually reads. The wrapper div per pair was already in the
 * markup, waiting for this. */
.dl { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--pad-tight); }
.dl > div {
  background: var(--bg-surface);
  border: 1px solid var(--sec-line, var(--line-soft));
  border-radius: var(--r-ctl);
  padding: 7px 9px;
  min-width: 0;
}
.dl dt { font-size: var(--t-micro); line-height: var(--lh-micro); font-weight: 600; color: var(--fg-3); }
.dl dd { font-size: var(--t-body); line-height: var(--lh-body); margin-top: 1px; }
.dl dd.num { font-size: var(--t-meta); }

/* Notice: one line that tells you something is about to happen on its own, and
 * the button that does it early. Tinted, hairlined, one radius — the tint is
 * the state, not decoration. */
.notice {
  display: flex; align-items: center; gap: var(--pad);
  padding: 10px var(--pad); border: 1px solid var(--line); border-radius: var(--r-ctl);
  background: var(--bg-sunken);
}
.notice-due  { border-color: var(--due-line);  background: var(--due-soft); }
.notice-late { border-color: var(--late-line); background: var(--late-soft); }
.notice-won  { border-color: var(--won-line);  background: var(--won-soft); }

/* Each notice carried a square tile with the glyph in it — bg-amber-100 /
 * text-amber-600 on the trial box, bg-indigo-100 / text-indigo-600 on the
 * auto-move one. --nt / --nt-soft are the same pair per state, so the tile
 * follows whichever variant the notice is wearing without a rule of its own. */
.notice      { --nt: var(--accent); --nt-soft: var(--accent-line); }
.notice-due  { --nt: var(--due);    --nt-soft: var(--due-line); }
.notice-late { --nt: var(--late);   --nt-soft: var(--late-line); }
.notice-won  { --nt: var(--won);    --nt-soft: var(--won-line); }
.notice-i {
  width: 30px; height: 30px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-ctl);
  background: var(--nt-soft); color: var(--nt);
}

/* Stage rail: where this lead is on the main path, as one bar rather than a row
 * of numbered circles. Off-path stages (Retarget, Lost) are said in words
 * underneath, because they are not a step on this line. */
.rail { display: flex; gap: 2px; }
.rail > span { flex: 1; height: 3px; border-radius: 1px; background: var(--bg-sunken); }
.rail > span.is-done { background: var(--won); }
.rail > span.is-now { background: var(--accent); }

/* Timeline: a hairline with the entries hung off it. No bubble per event. */
.tl { border-inline-start: 1px solid var(--sec-line, var(--line)); padding-inline-start: var(--pad); margin-inline-start: 3px; }
.tl > li { position: relative; padding-bottom: 12px; }
.tl > li::before {
  content: ""; position: absolute; inset-inline-start: calc(-1 * var(--pad) - 3px); top: 5px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--sec-fg, var(--fg-4));
}
.tl > li:last-child { padding-bottom: 0; }

/* Switch — the only control in the app that is a pill, because a pill is what
 * a switch is. 3px everywhere else still holds. */
.switch {
  position: relative; width: 34px; height: 18px; flex: none;
  border-radius: 999px; background: var(--line-strong);
  transition: background-color var(--dur) var(--ease); cursor: pointer;
}
.switch[aria-checked="true"] { background: var(--accent); }
.switch > span {
  position: absolute; top: 2px; inset-inline-start: 2px;
  width: 14px; height: 14px; border-radius: 999px; background: #fff;
  transition: inset-inline-start var(--dur) var(--ease);
}
.switch[aria-checked="true"] > span { inset-inline-start: 18px; }

/* =============================================================================
 * Skin: "classic" — the interface as it looked before the redesign.
 *
 * Kept because a team does not all move at once, and because being able to put
 * the two side by side is how the redesign gets argued on its merits rather
 * than on novelty.
 *
 * It is only tokens. Every value below is a variable the rest of the stylesheet
 * already reads, so switching skins is one attribute on <html> and a style
 * recalculation — no reflow of a different DOM, no second stylesheet, no
 * second build. Measured at 3ms median / 6ms worst on the Leads table with
 * 5,481 nodes, which is a fifth of a frame and happens once per click.
 *
 * What it therefore CANNOT restore: roughly half the redesign is structure,
 * behaviour and wording — the call sheet, the figure strips that replaced the
 * stat-card walls, the drawer's sections, sorting, the keyboard map, the seven
 * data states. Those live in the markup, not in a variable. Classic is the old
 * palette, type and shape on the new structure.
 * ========================================================================== */
:root[data-skin="classic"] {
  /* Tailwind slate, which is what this was built on */
  --rgb-ash-0:   255 255 255;  --rgb-ash-25:  248 250 252;
  --rgb-ash-50:  248 250 252;  --rgb-ash-100: 241 245 249;
  --rgb-ash-200: 226 232 240;  --rgb-ash-300: 203 213 225;
  --rgb-ash-400: 148 163 184;  --rgb-ash-450: 148 163 184;
  /* slate-500 is 4.34:1 on a slate-100 well, so the quiet text tone sits a
   * shade below it; slate-500 itself stays as the non-text tone above. */
  --rgb-ash-500: 93 107 129;   --rgb-ash-600: 71 85 105;
  --rgb-ash-700: 51 65 85;     --rgb-ash-800: 30 41 59;
  --rgb-ash-900: 15 23 42;     --rgb-ash-950: 2 6 23;

  /* indigo-600 */
  --rgb-signal-50: 238 242 255;  --rgb-signal-100: 224 231 255;
  --rgb-signal-200: 199 210 254; --rgb-signal-300: 165 180 252;
  --rgb-signal-400: 129 140 248; --rgb-signal-500: 99 102 241;
  --rgb-signal-600: 79 70 229;   --rgb-signal-700: 67 56 202;
  --rgb-signal-800: 55 48 163;

  /* One step darker than the originals (rose/amber/emerald 700 rather than
   * 600). The old palette put these three at 3.2-4.7:1 as body text, which is
   * below the floor — faithfully reproducing that would mean shipping a skin
   * that is knowingly harder to read. At 700 they still read as the old
   * colours and clear 4.5:1 on white, the canvas and a sunken well. */
  --rgb-late: 190 18 60;   --rgb-late-soft: 255 241 242;  --rgb-late-line: 254 205 211;
  --rgb-due:  180 83 9;    --rgb-due-soft:  255 251 235;  --rgb-due-line:  253 230 138;
  --rgb-won:  4 120 87;    --rgb-won-soft:  236 253 245;  --rgb-won-line:  167 243 208;

  --font-sans: Inter, "Segoe UI", Tahoma, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, monospace;

  /* The old shapes: generous radii and a shadow under every surface. */
  --r-ctl: 8px;
  --r-box: 16px;
  --shadow-overlay: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);
  --shadow-panel:   0 1px 2px 0 rgb(0 0 0 / .05);

  --chart-money: #059669;
  --chart-flow:  #4f46e5;
}
:root[data-skin="classic"].dark {
  --rgb-late: 251 113 133;  --rgb-late-soft: 76 5 25;   --rgb-late-line: 159 18 57;
  --rgb-due:  252 211 77;   --rgb-due-soft:  69 26 3;   --rgb-due-line:  146 64 14;
  --rgb-won:  52 211 153;   --rgb-won-soft:  2 44 34;   --rgb-won-line:  6 95 70;
  --late: rgb(var(--rgb-late)); --due: rgb(var(--rgb-due)); --won: rgb(var(--rgb-won));
  --late-soft: rgb(var(--rgb-late-soft)); --due-soft: rgb(var(--rgb-due-soft)); --won-soft: rgb(var(--rgb-won-soft));
  --late-line: rgb(var(--rgb-late-line)); --due-line: rgb(var(--rgb-due-line)); --won-line: rgb(var(--rgb-won-line));
  --chart-money: #34d399;
  --chart-flow:  #818cf8;
}

/* Panels floated on a shadow rather than sitting on a hairline. */
:root[data-skin="classic"] .panel { box-shadow: var(--shadow-panel); }

/* Stage colour is back. The redesign removed it on purpose — seven hues that
 * each meant a column and so meant nothing — which is exactly the thing a
 * side-by-side is meant to let people judge. Driven by data-status so the
 * console skin's markup needs no branch. */
:root[data-skin="classic"] .badge[data-status="NEW_LEAD"]        { background: #f1f5f9; color: #334155; }
:root[data-skin="classic"] .badge[data-status="TRIAL_ACTIVATED"] { background: #dbeafe; color: #1d4ed8; }
:root[data-skin="classic"] .badge[data-status="FOLLOW_UP"]       { background: #fef3c7; color: #b45309; }
:root[data-skin="classic"] .badge[data-status="PENDING_PAYMENT"] { background: #ede9fe; color: #6d28d9; }
:root[data-skin="classic"] .badge[data-status="PAID"]            { background: #d1fae5; color: #047857; }
:root[data-skin="classic"] .badge[data-status="RETARGET"]        { background: #ffedd5; color: #c2410c; }
:root[data-skin="classic"] .badge[data-status="LOST"]            { background: #ffe4e6; color: #be123c; }
:root[data-skin="classic"].dark .badge[data-status="NEW_LEAD"]        { background: #1e293b; color: #cbd5e1; }
:root[data-skin="classic"].dark .badge[data-status="TRIAL_ACTIVATED"] { background: #1e3a8a; color: #bfdbfe; }
:root[data-skin="classic"].dark .badge[data-status="FOLLOW_UP"]       { background: #78350f; color: #fde68a; }
:root[data-skin="classic"].dark .badge[data-status="PENDING_PAYMENT"] { background: #4c1d95; color: #ddd6fe; }
:root[data-skin="classic"].dark .badge[data-status="PAID"]            { background: #064e3b; color: #a7f3d0; }
:root[data-skin="classic"].dark .badge[data-status="RETARGET"]        { background: #7c2d12; color: #fed7aa; }
:root[data-skin="classic"].dark .badge[data-status="LOST"]            { background: #881337; color: #fecdd3; }
