/* Smooth Operator — shared "candy" web skin.
   Makes the staff web suite look like the mobile app (utils/ui.ts, Garden theme):
   purple accent, green money-hero, rainbow stats, big rounded cards, crisp deep
   shadows, Fredoka headings + Nunito body. Two modes only — dark (Garden Night)
   and light (Garden) — driven by <html data-mode="…"> from suite-rail.js's toggle.

   The whole suite shares one class vocabulary (.topbar/.tabs/.sec/.tb-btn/…), so
   this one file re-skins every panel. Everything is !important so it beats each
   page's base dark CSS and theme.js's palette rewrite. */

/* No @import here on purpose. An @import inside a stylesheet is the slowest
   possible way to load a font: the browser must fetch and parse THIS file
   before it even learns the font URL exists, so the two requests run in
   series and both block first paint. Every page that loads this skin already
   carries <link rel=preconnect> + a Google Fonts <link> in its own <head>;
   Fredoka rides along in that one request, in parallel with everything else. */

/* ---- TYPE ---------------------------------------------------------------
   Nunito was the candy pairing. Inter replaces it for everything that carries
   DATA, on one specific property rather than taste: Inter ships tabular
   figures by default — every numeral the same width — so a column of counts,
   times and money lines up without asking for an OpenType feature. Nunito is
   proportional, which is why the SLA clocks and the $ column jitter as the
   digits change. Inter also has a slashed zero, which matters on a screen
   where a dispatcher reads reference numbers aloud down a phone.
   Fredoka STAYS for the brand and page headings — it is the product's voice,
   and headings are the one place proportional figures cost nothing. */
html[data-mode] .mono, html[data-mode] .stat .v, html[data-mode] .llmeta,
html[data-mode] .appt-date, html[data-mode] .sla, html[data-mode] .done-stamp .amt{
  font-variant-numeric:tabular-nums !important;
  font-feature-settings:"tnum" 1, "zero" 1 !important;
}

/* ---- tokens: NEUTRAL, Apple-style ---------------------------------------- */
/* 2026-07-30: the warm Coast web skin is retired on his call — "overall colors
   are bad, let's try completely new style… apple style maybe monday style."
   That closes the warm-vs-neutral question that had been open since the 28th.

   The recipe is the one Apple and Monday both actually use: NEUTRAL greys with
   no hue cast for every surface and every piece of text, and exactly ONE
   saturated colour (blue) reserved for actions. Status colours appear only on
   status. What made the old skin tiring was not any single value but the cast:
   warm brown surfaces under cold blue actions meant the two halves of the
   screen pulled in different directions all day.

   Every pair below was scored before it was written down (WCAG 2 gate + APCA
   advisory, tools/check-contrast.mjs reads this file directly). The elevation
   ramp keeps Material 3's real numbers. Don't re-tune any of it by eye. */
html[data-mode="dark"]{
  /* Apple dark: near-black neutral ground, elevated neutral cards. The card
     step (1.14:1) is Material's surface-container step, and on a dark ground
     the tone step IS the elevation — a black shadow has nothing to darken. */
  --sk-bg:#111114; --sk-bg2:#19191D; --sk-card:#1E1E23; --sk-card2:#26262C;
  --sk-border:#34343B; --sk-border-soft:#26262C;
  /* A control sitting ON a card: one surface step above it, with an edge. */
  --sk-btn:#2A2A31; --sk-btn-line:#3B3B44;
  /* dim carries sentences → APCA Lc 75 on the card; faint carries short bold
     labels → Lc 60. Smallest mix toward white that clears the level. */
  --sk-text:#F5F5F7; --sk-dim:#CECED4; --sk-faint:#B4B4BD;
  /* One blue. #2563EB keeps white ink at 5.2:1 in BOTH modes, so a primary
     button is the same object everywhere; the light tint is what accent TEXT
     uses on dark, because a saturated fill colour is never readable type. */
  --sk-accent:#2563EB; --sk-accent-deep:#1D4ED8; --sk-accent-dim:rgba(96,146,255,.16);
  --sk-accent-text:#9DB8FA;
  --sk-hero1:#2563EB; --sk-hero2:#1D4ED8;
  --sk-success:#5CD692; --sk-danger:#FF9AA2; --sk-warn:#E9AC44;
  /* Two layers, hue-matched, negative spread — the ramp the app rebuilt onto in
     July (utils/ui.ts irisShadow). The old value was one 30px drop at 60%
     opacity: on a dark ground that reads as a smudge under every card rather
     than as light, and forty of them is the "hurts to look at" complaint. */
  /* ⚠️ On a dark ground a shadow barely reads — there is nothing for it to
     darken. Material's answer, and the right one: elevation is a LIGHTER
     surface, not a heavier shadow. So the shadow here is a thin contact edge
     only, and the lift comes from --sk-card sitting above --sk-bg. Piling on
     opacity instead just smears the gaps between cards, which is what the old
     30px/60% drop was doing to a column of forty. */
  /* Material's dark scheme keeps BOTH shadow layers and raises the surface
     tone as well — its containers run neutral 4 / 6 / 10 / 12 / 17 / 22, so
     its top container sits at 1.52:1 against the page. Ours stopped at
     1.10:1, which is why the lift was not landing: the shadow was doing the
     whole job on the one ground where a shadow can least afford to. The card
     tone moves up (see --sk-card) and the ambient layer comes back. */
  --sk-shadow:0 1px 2px 0 rgba(0,0,0,.45), 0 1px 3px 1px rgba(0,0,0,.28);
  --sk-shadow-soft:0 1px 2px 0 rgba(0,0,0,.30), 0 1px 3px 1px rgba(0,0,0,.16);
  --sk-shadow-raised:0 1px 2px 0 rgba(0,0,0,.45), 0 2px 6px 2px rgba(0,0,0,.28);
  --sk-shadow-accent:0 4px 6px -1px rgba(37,99,235,.30), 0 2px 4px -2px rgba(37,99,235,.30);
}
/* Apple light: #F5F5F7 is the exact page grey apple.com uses, white cards on
   it, and #1D1D1F is their body ink. The card-to-page step is 1.09:1 — the
   same as Material's surface-container — so the SHADOW draws the edge, which
   is what the Material-strength ramp below is for. */
html[data-mode="light"]{
  --sk-bg:#F5F5F7; --sk-bg2:#FFFFFF; --sk-card:#FFFFFF; --sk-card2:#F5F5F7;
  --sk-border:#E2E2E7; --sk-border-soft:#ECECF1;
  /* On light the card is white, so a control on it steps DOWN, not up. */
  --sk-btn:#F2F2F6; --sk-btn-line:#DEDEE4;
  --sk-text:#1D1D1F; --sk-dim:#55555E; --sk-faint:#6A6A73;
  --sk-accent:#2563EB; --sk-accent-deep:#1D4ED8; --sk-accent-dim:#E8EEFC;
  --sk-accent-text:#1D4ED8;
  --sk-hero1:#2563EB; --sk-hero2:#1D4ED8;
  --sk-success:#1B7A3D; --sk-danger:#D02533; --sk-warn:#93590A;
  /* ⚠️ THIS is why the light board looked flat, and it was not the hues.
     The old value was 10% opacity on both layers. Material 3's own elevation
     level 1 — read out of Google's implementation, material-web
     elevation/internal/_elevation.scss — is:

       key      0px 1px 2px 0px   at opacity 0.30
       ambient  0px 1px 3px 1px   at opacity 0.15

     Ours was a THIRD of the contact strength Material specifies, with a
     4px drop standing in for it. A far shadow at low opacity is a haze; a
     tight one at full strength is an edge, and an edge is what makes a card
     read as an object sitting on a page. Note the ambient layer's POSITIVE
     1px spread — the Tailwind ramp this came from uses negative spread,
     which pulls the shadow back under the card exactly where it is needed.

     Ink stays hue-matched rather than pure black: black on a tinted surface
     goes grey and dead. (utils/ui.ts, IRIS_INK.) Level 2 is the same key
     layer with a 0 2px 6px 2px ambient, used for the raised variant. */
  --sk-shadow:0 1px 2px 0 rgba(18,20,26,.30), 0 1px 3px 1px rgba(18,20,26,.15);
  --sk-shadow-soft:0 1px 2px 0 rgba(18,20,26,.18), 0 1px 3px 1px rgba(18,20,26,.09);
  --sk-shadow-raised:0 1px 2px 0 rgba(18,20,26,.30), 0 2px 6px 2px rgba(18,20,26,.15);
  --sk-shadow-accent:0 4px 6px -1px rgba(37,99,235,.22), 0 2px 4px -2px rgba(37,99,235,.22);
}

/* ---- radius SCALES with the size of the thing it rounds ------------------
   Everything in this file was 22px: a chip ended up as round as a sheet, and
   that uniform softness is the clearest "made by a beginner" tell there is.
   The app spans 4–18 for the same reason. */
html[data-mode]{ --sk-r-sm:6px; --sk-r-md:10px; --sk-r-lg:14px; --sk-r-xl:18px; }

/* ---- remap each panel's OWN design tokens to the Garden palette -----------
   The suite shares one variable vocabulary (--ink/--card/--line/--accent/…).
   Overriding those flips every var-based surface at once, in both modes,
   without needing to know each page's class names. !important beats theme.js's
   inline var writes. */
html[data-mode="dark"]{
  --ink:#F5F5F7 !important; --ink-2:#CECED4 !important; --ink-3:#B4B4BD !important;
  /* Mirrors the --sk-* block above; these two must move together or the pages
     that read --card get a different surface from the ones that read --sk-card. */
  --card:#1E1E23 !important; --card-2:#26262C !important;
  --panel:#1E1E23 !important; --panel-2:#19191D !important; --row:#26262C !important;
  --line:#34343B !important; --line-2:#43434C !important; --code-bg:#19191D !important;
  /* ⚠️ --row-hover comes from theme.js, which this skin overrides everywhere
     EXCEPT here — so the List view's row hover kept whatever palette theme.js
     had last written. On a dark board that surfaced as a near-WHITE band with
     pale grey text on it: the row you were pointing at was the one row you
     could not read. Claimed explicitly now, in both modes. */
  --row-hover:#26262C !important;
  /* The counterpart to --blue-soft. A semantic colour has TWO jobs — type on a
     card, and a fill under a badge — and on a dark theme those need opposite
     inks: the fills here are LIGHT, so white-on-them measures 2.0-2.5:1. Every
     count badge on the board was doing exactly that. */
  --on-danger:#2A090D !important; --on-warn:#241804 !important; --on-accent:#0C1B3A !important;
  /* --blue-soft carries TEXT and icons on cards, so it is the light tint, not
     the solid fill — a saturated fill colour is never readable type on dark. */
  --blue:#2563EB !important; --blue-soft:#9DB8FA !important; --accent:#2563EB !important;
  --violet:#9DB8FA !important; --indigo:#9DB8FA !important;
  --green:#5CD692 !important; --red:#FF9AA2 !important; --amber:#E9AC44 !important; --cyan:#67CBD9 !important;
  /* "Different colours for some, maybe the most used ones." Talk — reaching
     the technician — is one of the two buttons pressed all day, and it needed
     a hue that is not the send-blue beside it. Dark fills are LIGHT here, so
     the ink is near-black: #67CBD9 with white measures 1.89:1 and with
     #06232B it measures 8.67:1. Same reason --on-danger is dark on this mode.
     --warn-fill is the amber for FILLED chips, kept apart from --amber, which
     carries text and has to stay dark enough to read on a card. */
  --teal-fill:#67CBD9 !important; --on-teal:#06232B !important;
  --warn-fill:#E9AC44 !important; --on-warn-fill:#241804 !important;
  /* WhatsApp is somebody else's brand and people look for the green — but
     #25D366 on a button surface measures under 3:1 either way. These are the
     readable ends of the same green: 8.6:1 on dark, 4.8:1 on light. */
  --wa-ink:#4ADE80 !important;
}
html[data-mode="light"]{
  --ink:#1D1D1F !important; --ink-2:#55555E !important; --ink-3:#6A6A73 !important;
  --card:#FFFFFF !important; --card-2:#F5F5F7 !important;
  --panel:#FFFFFF !important; --panel-2:#F5F5F7 !important; --row:#F5F5F7 !important;
  --line:#E2E2E7 !important; --line-2:#D2D2D9 !important; --code-bg:#F5F5F7 !important;
  --row-hover:#F5F5F7 !important;   /* see the dark note above */
  /* Light mode's fills are DEEP, so white is right on danger and accent —
     amber flips with the mode like the rest: #93590A here is deep enough for
     white, #E9AC44 on dark is not. */
  --on-danger:#FFFFFF !important; --on-warn:#FFFFFF !important; --on-accent:#FFFFFF !important;
  --blue:#2563EB !important; --blue-soft:#1D4ED8 !important; --accent:#2563EB !important;
  --violet:#1D4ED8 !important; --indigo:#1D4ED8 !important;
  --green:#1B7A3D !important; --red:#D02533 !important; --amber:#93590A !important; --cyan:#0E7490 !important;
  /* Teal deep enough for white: 5.36:1.
     ⚠️ --warn-fill is NOT --amber. Amber had to be pushed to #93590A here so
     white type could sit on it, and #93590A is brown — which is what every
     filled amber chip on this mode actually looked like. Amber is the one hue
     where dark-on-light is the correct pairing; it is what a road sign does.
     #E8A33D with #241804 measures 8.06:1, brighter AND more readable than the
     brown was. --amber itself stays dark, because it still carries TEXT. */
  --teal-fill:#0E7490 !important; --on-teal:#FFFFFF !important;
  --warn-fill:#E8A33D !important; --on-warn-fill:#241804 !important;
  --wa-ink:#0F7A38 !important;
}

/* ---- base ---------------------------------------------------------------- */
html[data-mode] body{
  background:var(--sk-bg) !important;
  color:var(--sk-text) !important;
  font-family:'Inter',system-ui,-apple-system,'Segoe UI',sans-serif !important;
  letter-spacing:0 !important;
}
html[data-mode] .mono{ font-family:'JetBrains Mono',ui-monospace,monospace !important; }

/* headings + big numbers → Fredoka */
html[data-mode] .page-h,
html[data-mode] .sec-h .t,
html[data-mode] .crumb .path b,
html[data-mode] h1, html[data-mode] h2, html[data-mode] h3,
html[data-mode] .metric .v, html[data-mode] .stat .v{
  font-family:'Fredoka','Inter',sans-serif !important;
  letter-spacing:.2px !important;
}
html[data-mode] .page-d, html[data-mode] .crumb .path{ color:var(--sk-dim) !important; }
html[data-mode] .page-d b, html[data-mode] .crumb .path b{ color:var(--sk-text) !important; }

/* ---- top bar ------------------------------------------------------------- */
html[data-mode] .topbar{
  background:color-mix(in srgb, var(--sk-bg) 82%, transparent) !important;
  border-bottom:1px solid var(--sk-border) !important;
  backdrop-filter:blur(16px) !important;
}
html[data-mode] .back{
  background:var(--sk-card2) !important; border:1px solid var(--sk-border) !important;
  color:var(--sk-dim) !important; border-radius:var(--sk-r-md) !important;
}
html[data-mode] .back:hover{ background:var(--sk-accent-dim) !important; color:var(--sk-accent) !important; }

/* ---- A BREADCRUMB THAT NAMES A PLACE MUST GO THERE -----------------------
   "On the top left where it says what page we are, it should be pressable to
   go there from there." Every page put the destination in the crumb as plain
   text and hid the only way back inside a 34px chevron beside it — three pages
   did not even have the chevron. This is the one class that turns a crumb
   segment into the control it already looks like it should be.
   Deliberately NOT scoped to html[data-mode]: a page that has not booted the
   skin yet still needs its way home to work, and everything here inherits, so
   it takes each page's own palette. */
.crumb-go{font:inherit;color:inherit;background:none;border:0;margin:0 -5px;padding:2px 5px;
  border-radius:7px;cursor:pointer;text-decoration:none;display:inline-flex;align-items:center;
  gap:6px;transition:background .12s}
.crumb-go:hover{background:color-mix(in srgb,currentColor 13%,transparent)}
.crumb-go:hover, .crumb-go:hover b{text-decoration:underline;text-underline-offset:3px}
.crumb-go:active{transform:translateY(1px)}

/* pill buttons */
html[data-mode] .tb-btn{
  background:var(--sk-card2) !important; border:1px solid var(--sk-border) !important;
  color:var(--sk-dim) !important; border-radius:999px !important; font-family:'Inter',sans-serif !important;
  font-weight:700 !important; transition:transform .16s ease, box-shadow .16s ease !important;
}
html[data-mode] .tb-btn:hover{ color:var(--sk-text) !important; transform:translateY(-1px) !important;
  box-shadow:var(--sk-shadow-raised) !important; }
html[data-mode] .tb-btn.primary{
  background:var(--sk-accent) !important; border:none !important; color:#fff !important;
  box-shadow:var(--sk-shadow-accent) !important;
}
html[data-mode] .tb-btn.primary:hover{ transform:translateY(-2px) !important; }

/* ---- THE PRESS ----------------------------------------------------------
   ⚠️ Every one of these had a hover and none had an :active, which is the half
   people FEEL rather than notice: a control that lifts toward the pointer and
   then does nothing when clicked reads as a picture of a button. One pixel
   down and the shadow off is the whole trick, and it belongs here rather than
   on the board, because "make it cohesive" means the press is the same press
   in settings, the command center and the messenger.
   Resting shadow too — a flat rectangle is a label; a raised one is a button. */
html[data-mode] .tb-btn{ box-shadow:var(--sk-shadow-soft) !important; }
html[data-mode] .tb-btn:active,
html[data-mode] .tb-btn.primary:active,
html[data-mode] .tab:active,
html[data-mode] .btn:active,
html[data-mode] .btn-add:active{ transform:translateY(1px) !important; box-shadow:none !important; }
html[data-mode] .tb-btn:disabled,
html[data-mode] .tb-btn[disabled]{ box-shadow:none !important; transform:none !important; opacity:.55 !important;
  cursor:not-allowed !important; }
/* Keyboard gets the same clarity the mouse does. Offset so the ring sits
   outside the control rather than eating its edge. */
html[data-mode] :focus-visible{ outline:2px solid var(--sk-accent) !important; outline-offset:2px !important; }
@media (prefers-reduced-motion: reduce){
  html[data-mode] .tb-btn, html[data-mode] .tb-btn:hover, html[data-mode] .tb-btn:active,
  html[data-mode] .tab:active{ transform:none !important; }
}

/* ---- tabs ---------------------------------------------------------------- */
html[data-mode] .tabs{
  background:var(--sk-card2) !important; border:1px solid var(--sk-border) !important;
  border-radius:var(--sk-r-lg) !important;
}
html[data-mode] .tab{ color:var(--sk-dim) !important; border-radius:var(--sk-r-md) !important; font-family:'Inter',sans-serif !important; font-weight:700 !important; }
html[data-mode] .tab:hover:not(.on){ color:var(--sk-text) !important; }
html[data-mode] .tab.on{ background:var(--sk-accent) !important; color:#fff !important; box-shadow:var(--sk-shadow-accent) !important; }

/* ---- cards / sections / metrics ----------------------------------------- */
html[data-mode] .sec,
html[data-mode] .card,
html[data-mode] .panel,
html[data-mode] .health,
html[data-mode] .clock-card,
html[data-mode] .office-card,
html[data-mode] .list-panel{
  background:var(--sk-card) !important;
  border:1px solid var(--sk-border) !important;
  border-radius:var(--sk-r-xl) !important;
  box-shadow:var(--sk-shadow) !important;
  backdrop-filter:none !important;
}
/* colored KPI tiles keep their vivid fills (like the app's rainbow stats) */
html[data-mode] .metric{ border:none !important; border-radius:var(--sk-r-xl) !important; box-shadow:var(--sk-shadow) !important; }

/* command_center: search bar + filter/segment pills */
html[data-mode] .search{ background:var(--sk-card) !important; border:1px solid var(--sk-border) !important; border-radius:var(--sk-r-lg) !important; }
html[data-mode] .search input{ background:transparent !important; border:none !important; }
html[data-mode] .fbtn, html[data-mode] .b-net, html[data-mode] .b-priv{
  background:var(--sk-card2) !important; border:1px solid var(--sk-border) !important; color:var(--sk-dim) !important; border-radius:var(--sk-r-md) !important;
}
html[data-mode] .fbtn.on{ background:var(--sk-accent) !important; color:#fff !important; border-color:transparent !important; }
/* section-header icon badge → accent tint */
html[data-mode] .sec-h .t .si{ background:var(--sk-accent-dim) !important; color:var(--sk-accent) !important; border-radius:var(--sk-r-md) !important; }

/* inner rows / wells */
/* ⚠️ NOT .ld-tl .row — the lead modal's timeline steps match this selector by
   accident, so each of its four steps was drawn as a filled, bordered, rounded
   well. Four wells to say "created / assigned / started / completed". */
html[data-mode] .row:not(.ld-tl .row), html[data-mode] .item, html[data-mode] .svc-row, html[data-mode] .list-row{
  background:var(--sk-card2) !important; border:1px solid var(--sk-border-soft) !important; border-radius:var(--sk-r-lg) !important;
}

/* inputs */
html[data-mode] input:not([type=checkbox]):not([type=radio]),
html[data-mode] textarea, html[data-mode] select{
  background:var(--sk-bg2) !important; border:1px solid var(--sk-border) !important;
  color:var(--sk-text) !important; border-radius:var(--sk-r-md) !important; font-family:'Inter',sans-serif !important;
}
html[data-mode] input:focus, html[data-mode] textarea:focus, html[data-mode] select:focus{
  outline:none !important; border-color:var(--sk-accent) !important; box-shadow:0 0 0 3px var(--sk-accent-dim) !important;
}

/* old horizontal nav (hidden by suite-rail, styled here too if shown) */
html[data-mode] .nav a.on{ background:var(--sk-accent) !important; color:#fff !important; }

/* ---- inner components shared across panels (rows, chips, segments, wells) - */
html[data-mode] .svc-item,
html[data-mode] .charge,
html[data-mode] .editor,
html[data-mode] .mini-in,
html[data-mode] .well,
html[data-mode] .field,
html[data-mode] .sub-card,
html[data-mode] .office,
html[data-mode] .msg-row,
html[data-mode] .tech-item{
  background:var(--sk-card2) !important; border:1px solid var(--sk-border-soft) !important;
  border-radius:var(--sk-r-lg) !important; color:var(--sk-text) !important;
}
/* segmented / chip controls */
html[data-mode] .seg, html[data-mode] .ipick, html[data-mode] .tabs2{
  background:var(--sk-card2) !important; border:1px solid var(--sk-border) !important; border-radius:var(--sk-r-md) !important;
}
html[data-mode] .seg button, html[data-mode] .ipick button, html[data-mode] .rchip, html[data-mode] .skchip, html[data-mode] .chip{
  background:transparent !important; color:var(--sk-dim) !important; border-radius:var(--sk-r-sm) !important; font-family:'Inter',sans-serif !important;
}
html[data-mode] .rchip, html[data-mode] .skchip, html[data-mode] .chip{
  background:var(--sk-card2) !important; border:1px solid var(--sk-border) !important;
}
html[data-mode] .seg button.on, html[data-mode] .ipick button.on,
html[data-mode] .skchip.on, html[data-mode] .chip.on{
  background:var(--sk-accent) !important; color:#fff !important; border-color:transparent !important;
}
/* small icon buttons + add buttons */
html[data-mode] .iconbtn, html[data-mode] .add-btn{
  background:var(--sk-card2) !important; border:1px solid var(--sk-border) !important; color:var(--sk-dim) !important; border-radius:var(--sk-r-md) !important;
}
html[data-mode] .add-btn{ color:var(--sk-accent) !important; background:var(--sk-accent-dim) !important; border-color:transparent !important; font-family:'Inter',sans-serif !important; font-weight:700 !important; }
html[data-mode] .iconbtn.d{ color:var(--sk-danger) !important; }
html[data-mode] .iconbtn.e{ color:var(--sk-success) !important; }
/* muted sub-labels inside rows stay readable in light */
html[data-mode] .svc-item .sub, html[data-mode] .meta, html[data-mode] .muted{ color:var(--sk-dim) !important; }

/* ---- user_management -----------------------------------------------------*/
html[data-mode] .banner{ background:var(--sk-accent-dim) !important; border:1px solid var(--sk-border) !important; border-radius:var(--sk-r-lg) !important; color:var(--sk-text) !important; }
html[data-mode] .li, html[data-mode] .checks, html[data-mode] .gen, html[data-mode] .note{
  background:var(--sk-card2) !important; border:1px solid var(--sk-border-soft) !important; border-radius:var(--sk-r-md) !important; color:var(--sk-text) !important;
}
html[data-mode] .btn{ background:var(--sk-accent) !important; color:#fff !important; border:none !important; border-radius:var(--sk-r-md) !important; font-family:'Inter',sans-serif !important; font-weight:700 !important; }
html[data-mode] .btn.ghost{ background:var(--sk-card2) !important; color:var(--sk-dim) !important; border:1px solid var(--sk-border) !important; }
html[data-mode] .tag, html[data-mode] .mini, html[data-mode] .pill{ background:var(--sk-card2) !important; border:1px solid var(--sk-border) !important; color:var(--sk-dim) !important; border-radius:999px !important; }
html[data-mode] .tab.active, html[data-mode] .pill.on{ background:var(--sk-accent) !important; color:#fff !important; border-color:transparent !important; }
html[data-mode] .input{ background:var(--sk-bg2) !important; border:1px solid var(--sk-border) !important; color:var(--sk-text) !important; border-radius:var(--sk-r-md) !important; }

/* ---- live_map side panels (the map canvas itself is left alone) ----------*/
html[data-mode] .legend, html[data-mode] .detail, html[data-mode] .mc, html[data-mode] .sb-stat,
html[data-mode] .dt-cell, html[data-mode] .dt-job{
  background:var(--sk-card) !important; border:1px solid var(--sk-border) !important; border-radius:var(--sk-r-lg) !important; color:var(--sk-text) !important;
}
html[data-mode] .tk{ background:var(--sk-card2) !important; border:1px solid var(--sk-border-soft) !important; border-radius:var(--sk-r-md) !important; }
html[data-mode] .tk.sel{ border-color:var(--sk-accent) !important; box-shadow:0 0 0 2px var(--sk-accent-dim) !important; }

/* ---- operator board (keeps its OWN rail; recolour it candy) --------------*/
/* the board's whole navy accent → candy purple in one shot (rail active, logo,
   New-lead, primary buttons, Add-lead all read var(--nav-navy)) */
html[data-mode]{ --nav-navy:var(--sk-accent) !important; }
html[data-mode] .srlogo, html[data-mode] .sr-newlead{ box-shadow:0 10px 20px -6px var(--sk-accent) !important; }
html[data-mode] .srnav{ color:var(--sk-faint) !important; }
html[data-mode] .srnav:hover{ background:var(--sk-accent-dim) !important; color:var(--sk-accent) !important; }
html[data-mode] .srnav.on{ color:#fff !important; }
html[data-mode] .sr-office{ color:var(--sk-faint) !important; }
html[data-mode="dark"] .siderail{ background:var(--sk-bg2) !important; border-right:1px solid var(--sk-border) !important; box-shadow:14px 0 44px -22px rgba(0,0,0,.55) !important; }
html[data-mode="light"] .siderail{ background:#fff !important; border-right:1px solid var(--sk-border) !important; }
/* lead cards + tech pills use hardcoded dark rgba — flip to candy cards */
html[data-mode] .lead{ background:var(--sk-card) !important; border:1px solid var(--sk-border) !important; color:var(--sk-text) !important; }
html[data-mode] .tech-pill{ background:var(--sk-card2) !important; border:1px solid var(--sk-border-soft) !important; color:var(--sk-text) !important; }
html[data-mode] .pastebox{ background:var(--sk-card) !important; border:1px solid var(--sk-border) !important; }
/* board headings → Fredoka */
html[data-mode] .crumb .path b, html[data-mode] .rh-title, html[data-mode] .col-head .cn{ font-family:'Fredoka','Nunito',sans-serif !important; }
/* board rail light/dark toggle — icon flips with the mode via CSS, React-safe */
html[data-mode] .sr-modetoggle::after{ content:"\2600"; font-size:19px; line-height:1; }        /* ☀ in dark */
html[data-mode="light"] .sr-modetoggle::after{ content:"\263E"; }                                  /* ☾ in light */
html[data-mode] .sr-modetoggle svg{ display:none !important; }
/* lead-card inner wells + neutral action buttons (hardcoded deep-ocean rgba) */
html[data-mode="dark"] .svc-fields, html[data-mode="dark"] .assigned-to, html[data-mode="dark"] .la,
html[data-mode="dark"] .ld-f, html[data-mode="dark"] .ld-in, html[data-mode="dark"] .ld-sel, html[data-mode="dark"] .ld-ta{
  background:var(--sk-bg) !important;
}
html[data-mode="light"] .svc-fields, html[data-mode="light"] .assigned-to, html[data-mode="light"] .la,
html[data-mode="light"] .ld-f, html[data-mode="light"] .ld-in, html[data-mode="light"] .ld-sel, html[data-mode="light"] .ld-ta{
  background:var(--sk-card2) !important;
}

/* ---- Suite-wide sweep: every remaining well / input / chip / panel that
   hardcodes a deep-ocean rgba. Variable remapping can't see a literal colour,
   so each of these rendered dark-on-light. Audited per page:
     board            .num
     command_center   .obar
     settings         .editor .seg .tabs .charge-in .mini-in .skchip .iconbtn
     user_management  .input .li .checks .gen .tab
     live_map         .legend .mc
   (.nav is deliberately dark — the navy rail — so it is NOT included.) */
/* ⚠️ `.num` MEANS TWO DIFFERENT THINGS IN THIS SUITE, and the sweep below only
   knew about one of them. On the operator board it is a small INPUT WELL, which
   is why filling it is right. On client_reports.html it is a bare money figure
   inside a table cell — so the sweep drew a filled black box behind every
   number in every table on that page, and its `color` forced the green revenue
   and blue appointment figures back to plain ink. A figure inside a table is
   text, so it is excluded rather than fought with another !important. */
html[data-mode="dark"] .num:not(table .num), html[data-mode="dark"] .obar,
html[data-mode="dark"] .editor, html[data-mode="dark"] .seg, html[data-mode="dark"] .tabs,
html[data-mode="dark"] .charge-in, html[data-mode="dark"] .mini-in, html[data-mode="dark"] .skchip,
html[data-mode="dark"] .iconbtn, html[data-mode="dark"] .input, html[data-mode="dark"] .li,
html[data-mode="dark"] .checks, html[data-mode="dark"] .gen, html[data-mode="dark"] .tab,
html[data-mode="dark"] .legend, html[data-mode="dark"] .mc{
  background:var(--sk-bg) !important;
  border-color:var(--sk-line) !important;
  color:var(--sk-ink) !important;
}
html[data-mode="light"] .num:not(table .num), html[data-mode="light"] .obar,
html[data-mode="light"] .editor, html[data-mode="light"] .seg, html[data-mode="light"] .tabs,
html[data-mode="light"] .charge-in, html[data-mode="light"] .mini-in, html[data-mode="light"] .skchip,
html[data-mode="light"] .iconbtn, html[data-mode="light"] .input, html[data-mode="light"] .li,
html[data-mode="light"] .checks, html[data-mode="light"] .gen, html[data-mode="light"] .tab,
html[data-mode="light"] .legend, html[data-mode="light"] .mc{
  background:var(--sk-card2) !important;
  border-color:var(--sk-line) !important;
  color:var(--sk-ink) !important;
}
/* An active tab/segment must still read as selected after the sweep above. */
html[data-mode] .tab.on, html[data-mode] .tab.active, html[data-mode] .seg .on{
  background:var(--sk-accent) !important; color:#fff !important; border-color:transparent !important;
}
/* Popup shells. .modal / .feat-panel hardcode #0B2034, which variable
   remapping can't touch — so the lead-detail popup stayed deep-ocean navy in
   light mode while its inner wells (.ld-f above) correctly went white. */
html[data-mode] .modal, html[data-mode] .feat-panel{
  background:var(--sk-card) !important;
  border-color:var(--sk-line) !important;
  color:var(--sk-ink) !important;
}
/* ⚠️ The card action button. This skin claimed its COLOUR and left its
   BACKGROUND alone, and the background it kept is `rgba(8,20,32,.55)` — a
   half-transparent cold navy from the ocean-blue era, before any of this
   existed. Composited over the warm dark card (#2A2220) that lands on
   rgb(23,26,32): a near-black button, in the wrong hue family, on a brown
   card. That is the "cards look black on black, can't see the words".
   It gets a real surface now — one step above the card, the way Material
   raises a container — plus a hairline so the button has an edge even where
   the fill difference is small. */
html[data-mode] .la{
  color:var(--sk-dim) !important;
  background:var(--sk-btn) !important;
  border:1px solid var(--sk-btn-line) !important;
}
html[data-mode] .la:hover{ color:var(--sk-text) !important; border-color:var(--sk-border) !important; }
/* keep the coloured action variants (re-assert over the neutral .la rule) */
html[data-mode] .la.dispatch{ background:var(--sk-accent) !important; color:#fff !important; }
html[data-mode] .la.done{ background:rgba(22,179,126,.16) !important; color:var(--sk-success) !important; }
html[data-mode] .la.warn{ background:rgba(242,109,109,.16) !important; color:var(--sk-danger) !important; }
html[data-mode] .la.offered{ background:rgba(255,159,46,.16) !important; color:var(--sk-warn) !important; }

/* semantic keeps: money/success stays green, danger red, etc. via vars where pages use them */
html[data-mode] .demo-tag, html[data-mode] .live-tag{ border-radius:999px !important; }

/* retire theme.js's floating colour picker — a light/dark toggle replaces it */
html[data-mode] #so-theme-btn, html[data-mode] #so-theme-panel{ display:none !important; }

/* scrollbars */
html[data-mode] ::-webkit-scrollbar-thumb{ background:var(--sk-border) !important; }

/* ---- HOVER TOOLTIP, shared by the whole suite ---------------------------
   Built for the dispatch board's icon buttons and moved here so command
   center, messaging, settings and the rest get the SAME one — a tooltip that
   looks different on each page is three tooltips.

   Put `data-tip="…"` on anything. The 550ms delay is the design: instant
   tooltips fire on every mouse-cross and turn a toolbar into a flicker, too
   long and nobody ever sees one. The delay applies on the way IN only —
   leaving is instant, because a tooltip that lingers is chasing you.

   ⚠️ THIS IS THE FALLBACK NOW. A ::after is a CHILD, and a child cannot escape
   an ancestor that clips: the board's columns scroll, so a tip on a card
   button was cut off at the card's edge exactly when it had something long to
   say. suite-tip.js draws the real one — a single element on <body>, in the
   browser's top layer — and sets .tip-js on <html>, which turns everything
   below off. What is left here is what a page gets with JavaScript broken: a
   clipped tooltip, which still beats no tooltip. */
/* ⚠️ position:relative ONLY for the CSS fallback, and this is why: the rule
   used to apply to everything with a data-tip, at a specificity a page class
   cannot beat — so an element that was position:ABSOLUTE and happened to carry
   a tooltip was silently forced back into the flow. It cost me a map pin: the
   technician's dot on the board strip sat a pin-height low and was sliced by
   the bottom edge, with its own `position:absolute` losing to this.
   The real tooltip is a top-layer element positioned by JavaScript and needs
   nothing from its anchor; only the ::after fallback needs a containing block. */
html:not(.tip-js) [data-mode] [data-tip],
html[data-mode]:not(.tip-js) [data-tip]{ position:relative; }
html.tip-js [data-tip]::after{ content:none !important; }
html[data-mode] [data-tip]::after{
  content:attr(data-tip);
  position:absolute; bottom:calc(100% + 7px); left:50%; transform:translateX(-50%);
  background:var(--sk-text); color:var(--sk-bg);
  font-family:'Inter',system-ui,sans-serif;
  font-size:11px; font-weight:600; line-height:1.3; letter-spacing:0; text-transform:none;
  /* Was white-space:nowrap, which is right for "Cancel" and wrong for "Send an
     urgent alert — the tech gets a loud push". A tip that cannot wrap either
     runs off the screen or forces every label to be short enough for a
     toolbar, and several of these are a sentence because the control genuinely
     needs one. Short ones still come out on a single line: the box shrinks to
     its content and only the long ones reach the cap. */
  padding:5px 9px; border-radius:7px;
  white-space:normal; max-width:min(240px, 70vw); width:max-content; text-align:center;
  box-shadow:0 2px 8px rgba(0,0,0,.28);
  opacity:0; visibility:hidden; pointer-events:none; z-index:9500;
  transition:opacity .12s ease 0s, visibility 0s linear .12s;
}
html[data-mode] [data-tip]:hover::after,
html[data-mode] [data-tip]:focus-visible::after{
  opacity:1; visibility:visible;
  transition:opacity .14s ease .55s, visibility 0s linear .55s;
}
/* Near the top of a scrolling panel there is no room above, so flip it. */
html[data-mode] [data-tip][data-tip-below]::after{
  bottom:auto; top:calc(100% + 7px);
}
/* A VERTICAL rail needs it to the side: above a 46px icon in a stack of icons
   is on top of the icon above it, which names the wrong control. */
html[data-mode] [data-tip][data-tip-right]::after{
  bottom:auto; top:50%; left:calc(100% + 9px);
  transform:translateY(-50%); text-align:left;
}
@media (prefers-reduced-motion: reduce){
  html[data-mode] [data-tip]:hover::after{ transition-delay:.4s; }
}

/* ---- the REAL tooltip: one element, on <body>, in the top layer ----------
   Positioned by suite-tip.js. `popover` puts it in the browser's top layer,
   which is above every stacking context and outside every scroll container —
   so it cannot be clipped by a card, a column, a modal or a panel. The
   position:fixed and the z-index are for browsers without popover support;
   they are harmless where popover works, because a popover in the top layer
   ignores both. */
.sk-tip{
  position:fixed; margin:0; inset:auto; border:0; display:none;
  background:var(--sk-text, #1D1D1F); color:var(--sk-bg, #fff);
  font-family:'Inter',system-ui,-apple-system,sans-serif;
  font-size:11px; font-weight:600; line-height:1.35; letter-spacing:0; text-transform:none;
  padding:6px 10px; border-radius:8px;
  white-space:normal; max-width:min(280px, 72vw); width:max-content; text-align:left;
  box-shadow:0 4px 14px rgba(0,0,0,.28), 0 1px 3px rgba(0,0,0,.20);
  pointer-events:none; z-index:2147483000;
  opacity:0; transition:opacity .12s ease;
}
.sk-tip:popover-open{ display:block; }
.sk-tip.on{ opacity:1; }
@media (prefers-reduced-motion: reduce){ .sk-tip{ transition:none; } }

/* A modal outranks the mascot. Smooth's fixed root sits at z-index 8500 and
   every page's .modal-bg was at 100, so the robot and his speech bubble drew
   ON TOP of open dialogs — including the lead detail a dispatcher was typing
   into. One shared rule instead of twelve per-page fixes. */
html[data-mode] .modal-bg{ z-index:9000 !important; }

/* ---- MOTION -------------------------------------------------------------
   The board carries its own blanket reduced-motion rule. Eleven other pages
   in the suite carry none — messaging hub, settings, command center, manage
   technicians, user management, live map, owner reports, insights, client
   portal, provider portal, timeclock — and this file's own hover transforms
   and transitions run on every one of them. Putting the rule HERE is the
   only edit that reaches all twelve at once.

   Note what this does NOT do: it does not set `animation:none`. A spinner
   that stops spinning stops saying "still working". The W3C guidance is to
   remove motion that moves things THROUGH space, not to remove all feedback,
   so transforms collapse and durations go near-zero while opacity fades and
   in-place indicators survive. */
@media (prefers-reduced-motion: reduce){
  html[data-mode] *, html[data-mode] *::before, html[data-mode] *::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
  html[data-mode] *:hover{ transform:none !important; }
}

/* ---- FORCED COLORS (Windows High Contrast) -------------------------------
   Every surface in this file is a custom property, and forced-colors mode
   throws all of them away — so without this block the whole suite renders as
   unstyled black-on-white with borders that have collapsed to nothing. The
   system keywords below are the only colours that survive, and they are what
   the user actually chose. Borders get an explicit width because a border
   whose colour is currently `transparent` becomes invisible, not neutral. */
@media (forced-colors: active){
  html[data-mode] .card, html[data-mode] .sec, html[data-mode] .modal,
  html[data-mode] .feat-panel, html[data-mode] .lead, html[data-mode] .stat{
    border:1px solid CanvasText !important;
    background:Canvas !important;
    box-shadow:none !important;
  }
  html[data-mode] .btn, html[data-mode] .tb-btn, html[data-mode] .la,
  html[data-mode] .tab, html[data-mode] .add-btn, html[data-mode] .iconbtn{
    border:1px solid ButtonText !important;
    background:ButtonFace !important;
    color:ButtonText !important;
    forced-color-adjust:none;
  }
  /* Selection is carried by colour alone almost everywhere in this file; in
     forced colors that reads as "nothing is selected". */
  html[data-mode] .tab.on, html[data-mode] .tab.active, html[data-mode] .seg .on,
  html[data-mode] .rail-btn.on{
    background:Highlight !important; color:HighlightText !important;
    forced-color-adjust:none;
  }
  html[data-mode] :focus-visible{ outline:2px solid Highlight !important; outline-offset:2px !important; }
}

/* ---- FIGURES ------------------------------------------------------------
   Tabular figures were applied to six named classes, which left the ones that
   change most often — column counts, unread badges, list sub-lines, the money
   column — proportional. A count that goes 9 → 10 on a poll reflows its own
   row, and a dispatcher reads that flicker as "something happened". */
html[data-mode] .cn, html[data-mode] .cnt, html[data-mode] .rh-count,
html[data-mode] .num, html[data-mode] .amt, html[data-mode] .llsub,
html[data-mode] .badge, html[data-mode] .kpi, html[data-mode] .money,
html[data-mode] table td, html[data-mode] table th,
html[data-mode] input[type="number"], html[data-mode] input[inputmode="numeric"]{
  font-variant-numeric:tabular-nums !important;
  font-feature-settings:"tnum" 1, "zero" 1 !important;
}

/* ---- PROSE --------------------------------------------------------------
   `text-wrap: pretty` asks the browser to avoid a single-word last line. The
   clamped two-line address on a lead card orphans constantly without it, and
   an orphan reads as a truncation. Costs nothing where it is unsupported. */
html[data-mode] p, html[data-mode] .addr, html[data-mode] .svc,
html[data-mode] .note, html[data-mode] .ctext, html[data-mode] .empty{
  text-wrap:pretty;
}
