/* Grovia Attribution — SaaS layout */

/* Inter variable font, self-hosted from /public/fonts/ (was https://rsms.me/inter/inter.css,
   a personal-site SPOF that added a transatlantic RTT for the entire Indian user base).
   Mirrors the rsms.me declarations: a single variable woff2 covers weight 100–900 via
   font-weight: 100 900, with a matching italic face. font-display: swap renders with the
   system-ui fallback (declared on html/body below) while the font is fetched, so first
   paint is never blocked on the font network request. The <link rel="preload"> in
   index.html gets the upright woff2 fetched in parallel with the CSS. */
@font-face {
  font-family: "InterVariable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/InterVariable.woff2") format("woff2-variations");
}
@font-face {
  font-family: "InterVariable";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/InterVariable-Italic.woff2") format("woff2-variations");
}

* { box-sizing: border-box; }

/* Visually-hidden helper for screen-reader-only text (a11y). Keeps content
   in the accessibility tree while hiding it from sighted users — used to give
   icon-only / state-toggle buttons a spoken name without altering visuals.
   Standard "sr-only" recipe (Bootstrap/Tailwind). */
.sr-only {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

:root {
  /* Dark theme (default). Every color in the app references a variable so the
     light-theme override below can swap the whole palette in one place.
     Palette nudged up from pure-black-ish toward Linear/Vercel territory —
     enough lift that surfaces visibly layer instead of all blending into one
     dead-flat black. */
  --bg: #0e1117;
  --surface: #181c23;
  --surface-2: #1f242c;
  --surface-3: #272d36;
  --border: #2d3441;
  --border-strong: #3e4756;
  --text: #e7edf3;
  --muted: #8a96a5;
  --muted-2: #98a3b1; /* bumped from #6d7785 → passes WCAG AA on --bg (was 4.4:1, now 6.1:1) */
  --accent: #4ea3ff;
  --accent-2: #88c0ff;
  /* Primary-button pair (Linear/Stripe pattern): --accent is reserved for
     nav/links/borders/focus rings where contrast requirements are looser. For
     primary CTAs (Apply, Save, Sync, modal primaries, etc.) we use a darker
     blue so white text passes WCAG AA (4.5:1). Dark-theme accent #4ea3ff on
     white = 2.6:1 (FAIL); #2a7ec9 on white = 4.79:1 (AA pass). */
  --btn-primary-bg: #2a7ec9;
  --btn-primary-bg-hover: #3a8ed9;
  --btn-primary-fg: #ffffff;
  --green: #3fb86a;
  --red: #e0584a;
  --amber: #d6a02b;
  --row-hover: #1f252e;
  /* Per-theme overrides for things that can't be pure swaps (translucent tints,
     shadows, chart colors). The light theme defines its own variants below. */
  --shadow-card: 0 8px 22px rgba(0,0,0,0.45);
  --shadow-pop: 0 8px 24px rgba(0,0,0,0.40);
  --sticky-bg: rgba(14,17,23,0.92);
  --accent-soft: rgba(78,163,255,0.10);
  --accent-faint: rgba(78,163,255,0.04);
  --accent-mid: rgba(78,163,255,0.18);
  --green-soft: rgba(63,184,106,0.12);
  --green-mid: rgba(63,184,106,0.18);
  --green-strong: #5ed688;
  --red-soft: rgba(224,88,74,0.12);
  --red-mid: rgba(224,88,74,0.18);
  --red-strong: #f0786b;
  --red-banner-text: #ffb1a8;
  --amber-soft: rgba(214,160,43,0.12);
  --amber-mid: rgba(214,160,43,0.18);
  --amber-strong: #e0b850;
  --synthetic-tint: rgba(214,160,43,0.04);
  --synthetic-border: rgba(214,160,43,0.35);
  --grid-line: rgba(255,255,255,0.04);
  /* Approximate height of the sticky topbar — used by table headers that page-scroll
     (when NOT inside a .scroll-y container) so they sit below the topbar instead of
     under it. The .scroll-y selector overrides this to top:0 since scroll is contained. */
  --topbar-h: 62px;
  color-scheme: dark;
}

/* ====================================================================== */
/* LIGHT THEME. Activated via <body class="theme-light"> from theme toggle.
   Designed to keep the same information hierarchy as dark — same accent
   blues, just inverted surfaces with brighter, more saturated badges so
   they read well on white. */
/* ====================================================================== */
body.theme-light {
  --bg: #f4f6fa;
  --surface: #ffffff;
  --surface-2: #f1f4f9;
  --surface-3: #e4eaf2;
  --border: #d8dee6;
  --border-strong: #b8c2cd;
  --text: #1a2330;
  --muted: #5d6a78;
  --muted-2: #6a7480; /* tightened from #828c98 → passes WCAG AA on light --bg */
  --accent: #155ab8;             /* deeper blue for better contrast on white (WCAG AA on white + accent-soft) */
  --accent-2: #4c93ec;
  /* Primary CTA pair for light theme — slightly darker than --accent so white
     text clears 4.5:1 comfortably (#1e6fd9 on white is 4.85:1 — borderline). */
  --btn-primary-bg: #1860c2;
  --btn-primary-bg-hover: #1e6fd9;
  --btn-primary-fg: #ffffff;
  --green: #15703a; /* darkened so green-on-green-soft passes WCAG AA on white */
  --red: #b62719;   /* darkened so red-on-red-soft passes WCAG AA on white */
  --amber: #735206; /* darkened so amber-on-amber-soft passes WCAG AA on white */
  --row-hover: #eef2f7;
  --shadow-card: 0 1px 2px rgba(15,30,50,0.06), 0 4px 16px rgba(15,30,50,0.12); /* stronger so cards have weight on white bg */
  --shadow-pop: 0 6px 24px rgba(15,30,50,0.18);
  --sticky-bg: rgba(244,246,250,0.94);
  --accent-soft: rgba(30,111,217,0.10);
  --accent-faint: rgba(30,111,217,0.05);
  --accent-mid: rgba(30,111,217,0.20);
  --green-soft: rgba(31,138,74,0.10);
  --green-mid: rgba(31,138,74,0.14);
  --green-strong: #1f8a4a;
  --red-soft: rgba(201,56,41,0.10);
  --red-mid: rgba(201,56,41,0.14);
  --red-strong: #c93829;
  --red-banner-text: #9b2718;
  --amber-soft: rgba(160,121,15,0.12);
  --amber-mid: rgba(160,121,15,0.16);
  --amber-strong: #8a6708;
  --synthetic-tint: rgba(160,121,15,0.06);
  --synthetic-border: rgba(160,121,15,0.45);
  --grid-line: rgba(20,40,70,0.06);
  --select-arrow: %235d6a78;
  color-scheme: light;
}

html, body {
  margin: 0; padding: 0;
  background: var(--bg);
  color: var(--text);
  /* Inter (self-hosted, see @font-face at top of file) is the primary font.
     system-ui fallback so the page renders without blocking on the network.
     Inter ships with "InterVariable" as the variable family + "Inter" as the
     static fallback. */
  font-family: "InterVariable", "Inter", ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  font-size: 13.5px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Enable Inter's design features:
     • cv11 → slashed zero (distinguishes 0 from O in ID columns)
     • ss01 → single-storey 'a' (cleaner at small sizes)
     • cv02 → alternate 'a'
     • tabular numbers globally (numeric columns align without ad-hoc tabular-nums) */
  font-feature-settings: "cv11", "ss01", "cv02";
  font-variant-numeric: tabular-nums;
  text-rendering: optimizeLegibility;
}
/* For long-form prose (help boxes, modal bodies), prefer proportional digits
   for natural reading. Tables/KPIs override back to tabular-nums. */
.prose, p, .help-box, .grv-modal-body { font-variant-numeric: proportional-nums; }
.num, .kpi-value, .data-table td, .data-table th, .mono, code, kbd, samp {
  font-variant-numeric: tabular-nums;
}
a { color: var(--accent); text-decoration: none; cursor: pointer; }
a:hover { text-decoration: underline; }

button {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 5px 11px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 12.5px;
  font-family: inherit;
}
button:hover { background: var(--surface-3); }
button:disabled { opacity: 0.5; cursor: default; }

/* Topbar primary CTA — Refresh.
   Buyers hit this 100s of times a day after every chip flip, date change, or
   new-order suspicion. Promoting it to the primary-button pair (same tokens as
   .preset-btn.active / .view-tab.active) gives it the visual weight to be the
   obvious target in a 9-control topbar cluster and ends the misclick-on-
   Poll-Now foot-gun (mirrors the Sync-now demotion rationale at L1038-1042).
   The mobile @media block below (L762-771) intentionally overrides this with
   an icon-only ↻ glyph at small widths; do not change that. */
#refresh-btn {
  background: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
  border-color: var(--btn-primary-bg);
  font-weight: 600;
}
#refresh-btn:hover:not(:disabled) {
  background: var(--btn-primary-bg-hover);
  border-color: var(--btn-primary-bg-hover);
}
#refresh-btn::before {
  content: '\21BB'; /* ↻ */
  margin-right: 5px;
  font-size: 13px;
  line-height: 1;
}

/* Topbar debug action — Poll Now.
   Its own title attr says "normally polls every 15s automatically", so this is
   a force/debug action, not an everyday one. Demote it to a ghost-tertiary look
   (transparent bg, muted text, thinner padding) so it sits visibly below the
   primary Refresh in the visual hierarchy. Keep it discoverable — buyers
   occasionally need it when a Shopify webhook lag is suspected — but stop it
   from competing with Refresh for attention. */
#poll-now-btn {
  background: transparent;
  color: var(--muted);
  border-color: var(--border);
  padding: 4px 9px;
  font-size: 11.5px;
  font-weight: 500;
}
#poll-now-btn:hover:not(:disabled) {
  background: var(--surface-2);
  color: var(--text);
}

/* Section-aware topbar controls.
   Poll Now, the bell mute, and the RTO label/input/reset/pill only make sense on
   Shopify + Shipping (the modules whose math depends on live Shopify polling and
   the RTO assumption). On Meta / Google / Admin pages, they are noise — hide
   them entirely. `document.body.dataset.section` is set in app.js rerender(). */
body:not([data-section="shopify"]):not([data-section="shipping"]) #poll-now-btn,
body:not([data-section="shopify"]):not([data-section="shipping"]) #notif-mute-btn,
body:not([data-section="shopify"]):not([data-section="shipping"]) #rto-label,
body:not([data-section="shopify"]):not([data-section="shipping"]) #rto-status-pill {
  display: none !important;
}

input[type="date"], input[type="number"], input[type="text"], input[type="search"],
select {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 5px 9px;
  border-radius: 6px;
  font-size: 12.5px;
  font-family: inherit;
}
/* Native select-arrow uses dark theme-friendly chevron */
select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='%238a96a5' d='M0 0l5 6 5-6z'/></svg>");
  background-repeat: no-repeat;
  background-position: right 8px center;
  padding-right: 24px;
  cursor: pointer;
}
/* Light-theme select chevron is darker so it reads on light bg */
body.theme-light select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='%235d6a78' d='M0 0l5 6 5-6z'/></svg>");
}
select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
select option { background: var(--surface-2); color: var(--text); }
input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
input[type="number"] { width: 56px; }

/* ============== Global keyboard focus (WCAG 2.4.7) ==============
   `:focus-visible` only triggers on keyboard navigation (Tab/Shift+Tab),
   never on mouse clicks — so mouse users see zero change. Required because
   inputs/selects above set `outline: none` and the rest of the app (buttons,
   links, nav items, chips, tabs, presets, cmdk items, etc.) had no focus
   indicator at all, breaking keyboard-only navigation app-wide. */
button:focus-visible,
a:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: inherit;
}
/* Compact / inset components (sidebar items, chips, tabs, segmented controls)
   look better with the ring drawn inside their bounds rather than outside. */
.nav-item:focus-visible,
.chip:focus-visible,
.filter-chip:focus-visible,
.dt-chip:focus-visible,
.view-tab:focus-visible,
.preset-btn:focus-visible,
.subnav-item:focus-visible {
  outline-offset: -2px;
}

/* ============== Layout ============== */
.app {
  display: grid;
  grid-template-columns: 220px 1fr;
  min-height: 100vh;
}
.sidebar {
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
}
.sidebar-brand {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
}
/* Logo wrapper: SVG inherits this color, so theme-toggle automatically retints it. */
.logo {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;
  color: var(--green);
}
.logo svg { display: block; }
.brand-name { font-size: 15px; font-weight: 700; letter-spacing: 0.2px; }
/* Store switcher — sits just under the brand, scopes Meta + Shopify tabs. */
.store-switcher-wrap {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 18px 12px;
  border-bottom: 1px solid var(--border);
}
.store-switcher-label {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--muted-2, #8a8a93); font-weight: 600;
}
.store-switcher {
  flex: 1; min-width: 0;
  font-size: 13px; font-weight: 600;
  /* Right padding leaves room for the chevron the global `select` rule draws. */
  padding: 5px 26px 5px 9px; border-radius: 6px;
  border: 1px solid var(--border);
  /* IMPORTANT: set background-COLOR only — the `background` shorthand would reset
     background-repeat→repeat and position→0 0, which (with the theme chevron
     re-applied by `body.theme-light select`) tiles the arrow across the whole box. */
  background-color: var(--surface, #fff); color: inherit;
  cursor: pointer;
}

.nav {
  flex: 1;
  padding: 10px 8px;
  display: flex; flex-direction: column; gap: 2px;
  overflow-y: auto;
}
.nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px;
  border-radius: 6px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 500;
}
.nav-item:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.nav-item.active { background: var(--accent-soft); color: var(--accent); }
.nav-item .ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px;
  flex-shrink: 0;
  color: currentColor;
  opacity: 0.85;
}
.nav-item:hover .ico, .nav-item.active .ico { opacity: 1; }
/* Connect-prompt slot inside the Sync & Settings nav item. Empty by default
   (zero visual weight when configured); fship.js / google.js inject a
   "Connect" amber badge when the integration isn't wired up yet so first-touch
   users have an obvious starting point in the sidebar (parallels how Linear
   / Vercel surface unfinished onboarding state in the nav itself). */
.nav-item .nav-badge-slot { margin-left: auto; display: inline-flex; }
.nav-item .nav-badge-slot:empty { display: none; }
.nav-item .nav-badge-slot .badge {
  font-size: 10px; line-height: 1; padding: 3px 6px; border-radius: 4px;
  letter-spacing: 0.02em; text-transform: uppercase; font-weight: 600;
}

/* Connect-CTA empty state used when an integration (Fship, Google Ads MCC)
   isn't wired up yet. Replaces a plain inline text link with a foregrounded
   primary-button affordance so the action is obvious (Stripe/Linear pattern).
   Lives inside a regular .card so it inherits surface tokens / borders. */
.connect-empty {
  display: flex; align-items: center; gap: 16px;
  padding: 20px 22px;
}
.connect-empty .ce-icon {
  flex: 0 0 40px; width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 8px;
  background: var(--amber-mid);
  color: var(--amber-strong);
  font-size: 20px;
}
.connect-empty .ce-body { flex: 1; min-width: 0; }
.connect-empty .ce-title { font-weight: 600; font-size: 14px; color: var(--text); margin-bottom: 2px; }
.connect-empty .ce-sub   { font-size: 12.5px; color: var(--muted); }
.connect-empty .ce-cta {
  flex-shrink: 0;
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--btn-primary-bg); color: var(--btn-primary-fg);
  border: 1px solid var(--btn-primary-bg);
  padding: 8px 16px; border-radius: 6px;
  font-weight: 600; font-size: 13px; text-decoration: none;
  cursor: pointer; white-space: nowrap;
}
.connect-empty .ce-cta:hover {
  background: var(--btn-primary-bg-hover);
  border-color: var(--btn-primary-bg-hover);
  text-decoration: none;
}
@media (max-width: 600px) {
  .connect-empty { flex-direction: column; align-items: flex-start; gap: 12px; }
  .connect-empty .ce-cta { width: 100%; justify-content: center; }
}

.sidebar-footer {
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  font-size: 11px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* Theme toggle pill — lives in sidebar footer; flips dark <-> light + persists */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 12px;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  transition: background 80ms ease, border-color 80ms ease;
}
.theme-toggle:hover {
  background: var(--surface-3);
  border-color: var(--accent);
  color: var(--accent);
}
.theme-toggle-icon {
  font-size: 13px;
  line-height: 1;
  color: var(--accent);
}

.main {
  min-width: 0;
  display: flex; flex-direction: column;
}

/* ============== Topbar ============== */
.topbar {
  position: sticky; top: 0; z-index: 10;
  background: var(--sticky-bg);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
  padding: 12px 24px;
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  flex-wrap: wrap;
}
.topbar-left h1 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -0.1px;
}
.breadcrumbs {
  font-size: 12px;
  color: var(--muted);
  margin-top: 2px;
}
.breadcrumbs a { color: var(--muted); }
.breadcrumbs a:hover { color: var(--accent); }
.breadcrumbs .sep { margin: 0 6px; opacity: 0.5; }
.breadcrumbs .current { color: var(--text); }

.topbar-right {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.control { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--muted); }
.presets { display: inline-flex; gap: 2px; padding: 2px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 7px; }
.preset-btn {
  border: none; background: transparent; color: var(--muted);
  padding: 4px 10px; border-radius: 5px; font-size: 12px; font-weight: 500;
}
.preset-btn:hover { background: var(--surface-3); color: var(--text); }
.preset-btn.active { background: var(--btn-primary-bg); color: var(--btn-primary-fg); font-weight: 600; }

.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 9px;
  border-radius: 99px;
  font-size: 11px; font-weight: 600;
  border: 1px solid var(--border);
  white-space: nowrap;
}
.pill-green   { color: var(--green); background: var(--green-soft); border-color: var(--green-mid); }
.pill-amber   { color: var(--amber); background: var(--amber-soft); border-color: var(--amber-mid); }
.pill-red     { color: var(--red);   background: var(--red-soft);  border-color: var(--red-mid); }
.pill-muted   { color: var(--muted); background: var(--surface-3); border-color: var(--border); }

/* RTO% control — see index.html topbar and app.js syncRtoUi(). Default state is invisible;
   when the user overrides the value we add .rto-modified to wrap the input in an amber ring
   (peripheral signal) and reveal a × reset button. The matching #rto-status-pill (visible
   only when overridden) makes the assumption show up on screenshots. */
.rto-control { position: relative; }
.rto-control input#rto {
  /* Slight room for the × button on the right. Keep the visual weight subtle in
     the default state — this is a topbar control, not a primary action. */
  width: 56px;
  padding-right: 18px;
  transition: box-shadow 120ms ease, border-color 120ms ease;
}
.rto-control.rto-modified input#rto {
  /* Amber ring matches .pill-amber so the connection with the status pill is obvious.
     Using box-shadow (not outline) so it stacks cleanly with the existing border. */
  border-color: var(--amber-mid);
  box-shadow: 0 0 0 2px var(--amber-soft);
  color: var(--amber);
  font-weight: 600;
}
.rto-reset-btn {
  /* Sits inside the input's right padding. Hidden by default; revealed by syncRtoUi()
     when value != default. */
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 16px; height: 16px;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent;
  color: var(--amber);
  font-size: 14px; line-height: 1; font-weight: 700;
  cursor: pointer; padding: 0;
  border-radius: 3px;
}
.rto-reset-btn:hover { background: var(--amber-soft); }
.rto-reset-btn:focus-visible { outline: 2px solid var(--amber); outline-offset: 1px; }

.banner {
  margin: 12px 24px 0;
  padding: 10px 14px;
  border-radius: 8px;
  background: var(--red-soft);
  border: 1px solid var(--red-mid);
  color: var(--red-banner-text);
  font-size: 13px;
}

/* ============== Page content ============== */
.page-root { padding: 20px 24px 40px; }

/* KPI grid: auto-fit reflow so a 6-column-on-desktop layout never orphans the
   last cards on tablet widths, and an 8-KPI overview reflows cleanly to 5+3
   instead of squeezing into a strict grid. */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}
.kpi {
  /* Same subtle gradient as .card — Vercel/Linear pattern. */
  background: linear-gradient(180deg, var(--surface) 0%, var(--surface-2) 100%);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 13px 16px;
  position: relative;
  display: flex;
  flex-direction: column;
  /* min height keeps cards even when some have sparklines and others don't */
  min-height: 88px;
  transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;
}
.kpi:hover {
  /* Tiny depth lift on hover — Vercel deployment-card pattern. Cheap delight. */
  border-color: var(--border-strong);
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
}
body.theme-light .kpi:hover { box-shadow: 0 2px 8px rgba(40, 60, 100, 0.06); }
.kpi-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--muted); margin-bottom: 5px; }
.kpi-value { font-size: 22px; font-weight: 700; letter-spacing: -0.3px; font-variant-numeric: tabular-nums; line-height: 1.1; }
.kpi-sub { font-size: 11px; color: var(--muted); margin-top: 3px; min-height: 1em; display: flex; align-items: center; gap: 6px; }
/* Period-over-period delta badge inside .kpi-sub. Stripe/Northbeam pattern: */
/*   ↑ 12.4%  in green when good     ↓ 3.1%  in red when bad      —  when no prior */
.kpi-delta {
  display: inline-flex; align-items: center; gap: 2px;
  font-weight: 600;
  font-size: 11px;
  padding: 1px 5px;
  border-radius: 3px;
  font-variant-numeric: tabular-nums;
}
.kpi-delta-good { color: var(--green-strong); background: rgba(94, 214, 136, 0.10); }
.kpi-delta-bad  { color: var(--red-strong);   background: rgba(244, 102, 102, 0.10); }
.kpi-delta-flat { color: var(--muted); }
body.theme-light .kpi-delta-good { background: rgba(31, 138, 74, 0.10); }
body.theme-light .kpi-delta-bad  { background: rgba(196, 50, 50, 0.10); }
/* Inline sparkline pinned to bottom-right of the KPI card. Auto-coloured to
   match delta direction (good=green, bad=red, flat=muted) by inline color. */
.kpi-spark {
  position: absolute;
  bottom: 10px;
  right: 12px;
  opacity: 0.85;
  pointer-events: none;
}
.kpi-spark svg { display: block; }
.kpi-spark svg .spark { stroke-width: 1.5; }
/* On narrow screens the sparkline competes with the KPI value — hide it */
@media (max-width: 600px) { .kpi-spark { display: none; } }

/* Primary KPI: 2x visual weight. Use for the headline metric on a page (e.g. Real CPA,
   Real ROAS on Meta Overview). The whole pitch of Real Attribution is "Real beats Meta",
   so Real values should dominate Meta-claimed comparison values. */
.kpi.kpi-primary {
  background: linear-gradient(135deg, var(--accent-faint), var(--surface));
  border-color: var(--accent-mid);
}
.kpi.kpi-primary .kpi-label { color: var(--accent); font-weight: 700; }
.kpi.kpi-primary .kpi-value { font-size: 30px; color: var(--text); }

/* Section cards.
   2026 SaaS pattern (Vercel / Linear / Stripe / Notion):
   subtle 180°-gradient from surface → surface-2 instead of flat fill — adds
   the smallest hint of depth without "boxy" look. Hairline 1px border at
   reduced opacity reads as a divider, not a frame. */
.card {
  background: linear-gradient(180deg, var(--surface) 0%, var(--surface-2) 100%);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  margin-bottom: 14px;
}
.card-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 10px; }
.card-head h2 { font-size: 13.5px; margin: 0; font-weight: 600; }
.card-head .hint { font-size: 11.5px; color: var(--muted); }
.hint { font-size: 11.5px; color: var(--muted); }
.hint.pad { padding: 14px; }
.two-col { display: grid; grid-template-columns: 1.6fr 1fr; gap: 14px; }

/* Trend chart container — fixed height, no layout shift */
.trend-wrap {
  height: 200px;
  position: relative;
  margin-top: 4px;
}
.trend-wrap canvas { position: absolute; inset: 0; width: 100% !important; height: 100% !important; }

/* Mini sparkline (compact, scoped) */
.sparkline {
  display: inline-block; vertical-align: middle;
  height: 28px; width: 100px;
}
/* Inline sparkline cells in data tables (Accounts/Campaigns trend column).
   Pattern from Stripe Dashboard, Triple Whale, Northbeam. */
.spark-cell {
  vertical-align: middle !important;
  /* svg children are display:block so the cell hugs them — no extra whitespace */
}
.spark-cell svg { display: inline-block; vertical-align: middle; }

/* Tables */
table.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
}
table.data-table th, table.data-table td {
  border-bottom: 1px solid var(--border);
  padding: 7px 8px;
  text-align: left;
  vertical-align: middle;
}
table.data-table th {
  font-weight: 600;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--muted);
  /* Use surface-2 (slightly darker than card body gradient bottom) so the
     sticky header reads as floating above the rows. Add a hair-thin inset
     bottom border so the boundary stays visible even when scrolled —
     Stripe Dashboard / Linear list-view pattern. */
  background: var(--surface-2);
  box-shadow: inset 0 -1px 0 var(--border);
  position: sticky; top: 0; z-index: 5;
}
table.data-table tbody tr { transition: background 80ms ease; }
table.data-table tbody tr:hover { background: var(--row-hover); }
table.data-table tbody tr.row-clickable { cursor: pointer; }
table.data-table tbody tr.row-clickable:hover td:first-child { color: var(--accent); }
table.data-table .num { text-align: right; }
table.data-table .col-id {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  word-break: break-all;
  max-width: 420px;
}
table.data-table.tight th, table.data-table.tight td { padding: 5px 8px; font-size: 12px; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace; font-size: 11.5px; word-break: break-all; }
.tag-cod { color: var(--amber); }
.tag-prepaid { color: var(--green); }
.tag-cancelled { color: var(--red); text-decoration: line-through; }
.tag-broken { color: var(--red); }
.tag-unattr { color: var(--muted); }
.cell-truncate { max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Sortable headers */
table.data-table th[data-sort] { cursor: pointer; user-select: none; }
table.data-table th[data-sort]:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
table.data-table th[data-sort]::after {
  content: "↕"; margin-left: 4px; color: var(--border-strong); font-weight: normal;
}
table.data-table th.sort-active { color: var(--accent); }
table.data-table th.sort-active.sort-desc::after { content: "↓"; color: var(--accent); }
table.data-table th.sort-active.sort-asc::after  { content: "↑"; color: var(--accent); }

/* Filter chips */
.chips { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.chip {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--muted);
  padding: 4px 10px;
  border-radius: 99px;
  font-size: 12px;
  cursor: pointer;
}
.chip:hover { background: var(--surface-3); color: var(--text); }
.chip.active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}

.toolbar {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 10px;
}
.toolbar input[type="search"], .toolbar input[type="text"] {
  flex: 1; min-width: 200px;
  padding: 6px 10px; font-size: 12.5px;
}
.toolbar .row-count { font-size: 11.5px; color: var(--muted); margin-left: auto; }

/* Inner-scroll container for long tables. Responsive height so the table window
   adapts to the viewport (was hardcoded 580px, which left huge dead space on
   tall monitors and eclipsed content on short ones). */
.scroll-y { max-height: calc(100vh - 280px); min-height: 360px; overflow-y: auto; }

/* Breadcrumb back chip */
.back-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px; border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--muted);
  font-size: 11.5px;
  cursor: pointer;
}
.back-chip:hover { background: var(--surface-3); color: var(--text); }

/* Toasts */
#toast-stack {
  position: fixed; right: 20px; bottom: 20px;
  display: flex; flex-direction: column; gap: 8px; z-index: 50;
}
.toast {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--green);
  border-radius: 8px;
  padding: 10px 14px;
  font-size: 13px;
  min-width: 280px;
  box-shadow: var(--shadow-card);
  animation: slidein 200ms ease-out;
}
.toast strong { color: var(--green); }
@keyframes slidein { from { transform: translateY(8px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

/* Totals footer row */
table.data-table tfoot tr.totals-row td {
  border-top: 1px solid var(--border-strong);
  background: var(--surface-2);
  font-weight: 600;
  font-size: 12.5px;
  color: var(--text);
  position: sticky;
  bottom: 0;
  z-index: 1;
}
table.data-table tfoot tr.totals-row td:first-child {
  color: var(--accent);
  letter-spacing: 0.3px;
  text-transform: uppercase;
  font-size: 11px;
}
table.data-table.tight tfoot tr.totals-row td { font-size: 12px; }

/* View tabs (sub-tabs within a drill-down) */
.view-tabs {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-bottom: 14px;
}
.view-tab {
  padding: 6px 14px;
  border-radius: 6px;
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}
.view-tab:hover { background: var(--surface-3); color: var(--text); text-decoration: none; }
.view-tab.active {
  background: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
  font-weight: 600;
}

/* Responsive */
@media (max-width: 1100px) {
  .kpi-grid { grid-template-columns: repeat(3, 1fr); }
  .two-col { grid-template-columns: 1fr; }
}
/* ===========================================================================
   MOBILE — off-canvas sidebar drawer (≤900px covers all tablet-portrait + phone).
   Replaces an earlier "sidebar as horizontal scrolling strip at 880px" approach
   which broke down once we had 20+ nav items (Meta + Google + Shopify + Shipping
   + Admin). Hamburger button (added to topbar) opens the drawer; backdrop tap
   or nav-item tap closes it. JS handler lives in index.html.
   =========================================================================== */
@media (max-width: 900px) {
  .app { grid-template-columns: 1fr; }
  /* Sidebar slides in from the left over the main content. height: 100dvh
     uses the DYNAMIC viewport so iOS Safari shrinks with the URL bar on
     screen (vs 100vh which is the LARGEST viewport — pushed the Sign-out +
     theme-toggle below the visible edge when the URL bar was visible).
     100vh kept as a fallback for browsers that don't support dvh. */
  .sidebar {
    position: fixed; top: 0; left: 0;
    width: 260px; max-width: 80vw;
    height: 100vh;
    height: 100dvh;
    z-index: 100;
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    box-shadow: 0 0 24px rgba(0,0,0,0.18);
    overflow-y: auto;
  }
  body.sidebar-open .sidebar { transform: translateX(0); }
  /* Backdrop — only while drawer is open */
  body.sidebar-open::before {
    content: ''; position: fixed; inset: 0;
    background: rgba(0,0,0,0.4); z-index: 99; cursor: pointer;
  }
  /* Hamburger button — visible only at this breakpoint */
  .hamburger-btn {
    display: inline-flex !important;
    align-items: center; justify-content: center;
    width: 44px; height: 44px;
    background: transparent; border: none;
    font-size: 22px; cursor: pointer;
    color: var(--text); padding: 0;
    margin-right: 6px;
    border-radius: 8px;
  }
  .hamburger-btn:hover { background: var(--surface-2); }
  .hamburger-btn:active { background: var(--surface-3); }
  /* Topbar: hide noise on small screens — keep essentials only (hamburger, title,
     date, freshness pill, refresh). Refresh becomes icon-only to save width;
     pill stays visible so a stale snapshot is never silent. */
  .topbar-right > label.control,
  #poll-now-btn,
  .topbar-bell-btn, .tour-help-btn,
  .cmdk-trigger .cmdk-trigger-text, .cmdk-trigger .cmdk-trigger-kbd {
    display: none;
  }
  .cmdk-trigger { padding: 8px 10px; min-width: 0; }
  /* Icon-only refresh: hide the text label via font-size:0, render a ↻ glyph. */
  #refresh-btn {
    padding: 8px 10px;
    font-size: 0;
    line-height: 1;
  }
  #refresh-btn::before {
    content: '\21BB'; /* ↻ */
    font-size: 16px;
    line-height: 1;
  }
  /* Tighten the freshness pill so it fits next to the date trigger. */
  .topbar-right .pill {
    padding: 4px 8px;
    font-size: 11px;
  }
  /* Tables: sticky first column so the row label stays visible while scrolling right.
     Surface background prevents the scrolled content from showing through. */
  table.data-table th:first-child,
  table.data-table td:first-child {
    position: sticky; left: 0;
    background: var(--surface);
    z-index: 2;
    box-shadow: 2px 0 4px -2px rgba(0,0,0,0.08);
  }
  /* Horizontal scroll inside the existing scroll wrappers */
  .scroll-y { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  /* Sortable headers — bigger tap surface */
  table.data-table th[data-sort] { padding-top: 12px; padding-bottom: 12px; }
}
/* Phone-sized: 44pt touch targets (iOS HIG) for the nav + chips + small buttons */
@media (max-width: 768px) {
  .nav-item, .filter-chip, button.btn-small {
    min-height: 44px;
    padding-top: 10px; padding-bottom: 10px;
  }
  .nav-item { padding-left: 14px; padding-right: 14px; }
}
/* Desktop: hide the hamburger entirely (sidebar is always visible at this size) */
@media (min-width: 901px) {
  .hamburger-btn { display: none !important; }
}
/* ===========================================================================
   Mobile-first Overview — the dashboard a media buyer pulls up on their phone
   between meetings. Stack KPIs single-column with the headline metrics taking
   the full width, hide the trend chart (not useful at this size), and use
   bigger tap targets. Driven entirely by viewport width — same page, just
   restructured at small sizes.
   =========================================================================== */
@media (max-width: 600px) {
  .kpi-grid { grid-template-columns: 1fr 1fr; gap: 8px; }
  /* Primary KPIs (Real CPA / Real ROAS) take the full row — the metric that
     matters most when you're glancing at a phone. */
  .kpi.kpi-primary { grid-column: 1 / -1; }
  .kpi.kpi-primary .kpi-value { font-size: 36px; }
  .kpi { padding: 11px 14px; }
  .kpi-value { font-size: 20px; }
  .topbar { padding: 10px 14px; gap: 8px; }
  .topbar-left h1 { font-size: 16px; }
  .topbar-right { gap: 6px; }
  .topbar-right .pill { font-size: 10px; padding: 2px 7px; }
  .topbar-right > .control, .topbar-right > button { font-size: 12px; }
  .page-root { padding: 12px 14px 60px; }
  /* Trend chart adds noise at this size and never tells you anything in 1-2 day
     ranges — collapse it to save the scroll real estate. */
  .trend-wrap { max-height: 150px; }
  /* Bigger tap targets for primary actions on mobile */
  button, .btn-small, .nav-item { min-height: 36px; }
  /* Help / status text stays readable */
  .ra-status-strip { padding: 8px 12px; gap: 10px; font-size: 11.5px; }
  /* Mobile-only utility — hide elements that don't matter on phone */
  .mobile-hide { display: none !important; }
  /* Modals: use almost-full viewport on phone for legibility */
  .grv-modal { width: 96vw; }
}
/* Very narrow screens (sub-380px / older phones in landscape) */
@media (max-width: 380px) {
  .kpi-grid { grid-template-columns: 1fr; }
  .kpi.kpi-primary .kpi-value { font-size: 32px; }
}

/* =========================================================================
   Real Attribution — sidebar divider + subnav + badges + help box
   ========================================================================= */

.nav-divider {
  margin: 14px 12px 4px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted-2);
}
.nav-divider span { display: block; padding-left: 4px; }
.nav-divider:empty { padding-top: 0; margin-bottom: 0; }

/* Sub-navigation inside Real Attribution pages */
.subnav {
  display: flex;
  gap: 4px;
  padding: 10px 0 0;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.subnav-item {
  padding: 8px 14px;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 6px 6px 0 0;
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 500;
  text-decoration: none;
  margin-bottom: -1px;
}
.subnav-item:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
.subnav-item.active {
  color: var(--text);
  background: var(--surface);
  border-color: var(--border);
  border-bottom-color: var(--surface);
  font-weight: 600;
}

/* Inline status strip — fx rate, last sync, sync button */
.ra-status-strip {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 14px;
  margin-bottom: 14px;
  font-size: 12px;
}
.ra-status-strip .hint { color: var(--muted); }
.ra-status-strip .hint strong { color: var(--text); }
.btn-small {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 3px 10px;
  border-radius: 5px;
  font-size: 11.5px;
  cursor: pointer;
  margin-left: auto;
}
.btn-small:hover { background: var(--surface-3); }

/* Help / "how this is calculated" expandable */
.help-box {
  background: var(--accent-faint);
  border: 1px solid var(--accent-mid);
  border-radius: 8px;
  padding: 0 14px;
  margin-bottom: 14px;
  font-size: 12.5px;
}
.help-box summary {
  cursor: pointer;
  padding: 10px 0;
  font-weight: 600;
  color: var(--accent-2);
  list-style: none;
  user-select: none;
}
.help-box summary::-webkit-details-marker { display: none; }
.help-box summary::before {
  content: '▸ ';
  display: inline-block;
  margin-right: 4px;
  transition: transform 0.15s ease;
}
.help-box[open] summary::before { transform: rotate(90deg); }
.help-box p { margin: 6px 0; color: var(--text); line-height: 1.55; }
.help-box ul { margin: 6px 0 10px; padding-left: 22px; }
.help-box li { margin: 3px 0; line-height: 1.55; }
.help-box li strong, .help-box p strong { color: var(--accent-2); }
.help-box .hint { color: var(--muted); font-style: italic; }

/* "Estimated" badge for pro-rata-allocated values */
.est-badge {
  display: inline-block;
  padding: 1px 5px;
  margin-left: 4px;
  background: var(--amber-mid);
  color: var(--amber);
  border: 1px solid var(--synthetic-border);
  border-radius: 4px;
  font-size: 9.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  cursor: help;
  vertical-align: middle;
}

/* Colored badges (inflation, leak, status). Linear-style: a tiny colored dot
   + the label, instead of just a colored pill. Reads faster, more compact,
   accessible (the dot adds a non-color signal — colorblind-friendly). */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
  line-height: 1.4;
}
.badge::before {
  content: '';
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
  /* For colorblind users, the dot's position + shape carries info redundantly */
}
.badge-red    { background: var(--red-mid); color: var(--red-strong); border: 1px solid var(--red-mid); }
.badge-green  { background: var(--green-mid); color: var(--green-strong); border: 1px solid var(--green-mid); }
.badge-amber  { background: var(--amber-mid); color: var(--amber-strong); border: 1px solid rgba(214, 160, 43, 0.30); }
.badge-muted  { background: var(--surface-3); color: var(--muted); border: 1px solid var(--border); }
.badge-muted::before { opacity: 0.6; } /* less visual weight for muted/archived */
.badge-red-text   { color: var(--red-strong); }
.badge-green-text { color: var(--green-strong); }

/* Settings form inside Sync & Settings page */
.settings {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding: 12px 14px;
  align-items: end;
}
.settings .control { margin-right: 6px; }
.settings .btn {
  background: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
  border: 1px solid var(--btn-primary-bg);
  padding: 6px 16px;
  border-radius: 6px;
  font-weight: 600;
}
.settings .btn:hover { background: var(--btn-primary-bg-hover); border-color: var(--btn-primary-bg-hover); }

/* Tooltip-like cursor on est badges */
.row-clickable { cursor: pointer; }
.row-clickable:hover { background: var(--row-hover); }
/* a11y: keyboard focus ring for row-as-link (WCAG 2.4.7 Focus Visible).
   Uses inset shadow so it stays inside the row and doesn't shift layout. */
.row-clickable:focus { outline: none; }
.row-clickable:focus-visible {
  outline: none;
  background: var(--row-hover);
  box-shadow: inset 2px 0 0 var(--accent);
}

/* Synthetic / system-generated rows (e.g. "(Unallocated)" when totalAttributed=0) */
.row-synthetic td {
  font-style: italic;
  color: var(--muted);
  background: var(--synthetic-tint);
}
.row-synthetic td:first-child { border-left: 2px solid var(--synthetic-border); }

/* Empty Meta data banner shown on Real Attribution pages before first sync */
.empty-meta-banner {
  background: var(--accent-faint);
  border: 1px solid var(--accent-mid);
  border-radius: 8px;
  padding: 14px 18px;
  margin-bottom: 14px;
  color: var(--text);
  font-size: 13px;
  line-height: 1.55;
}
.empty-meta-banner strong { color: var(--accent-2); }
.empty-meta-banner .btn-small { margin-left: 12px; }

/* Sync-now card on the Sync & Settings page. Lives here (not in the topbar /
   status strip) so that hitting it is a deliberate two-step action: navigate
   to settings → click. Prevents the "click Sync now thinking it's a refresh"
   foot-gun media buyers kept hitting. The Refresh button on every page is what
   they really want 99% of the time. */
.sync-now-card { padding: 16px 20px; }
.sync-now-row { display: flex; align-items: center; gap: 20px; }
.sync-now-text { flex: 1; min-width: 0; }
.sync-now-title { font-weight: 700; font-size: 15px; color: var(--text); margin-bottom: 4px; }
.sync-now-sub { font-size: 12.5px; color: var(--muted); line-height: 1.55; }
.sync-now-sub strong { color: var(--text); font-weight: 600; }
.sync-now-btn { flex-shrink: 0; min-width: 110px; }
@media (max-width: 600px) {
  .sync-now-row { flex-direction: column; align-items: stretch; }
  .sync-now-btn { width: 100%; }
}

/* Sync error panel — full diagnostic shown when Meta sync has issues. Pattern:
   GitHub Actions failure card / Stripe webhook error detail / Sentry issue panel.
   Replaces the old cryptic "sync error" badge — when this panel is absent, sync
   is genuinely fine. When present, it tells you exactly what's wrong, what it
   means, what to do, which accounts are affected, and shows the raw error. */
.sync-panel {
  border-radius: 10px;
  padding: 14px 18px;
  margin-bottom: 14px;
  font-size: 13px;
  line-height: 1.55;
  border: 1px solid;
}
.sync-panel-red    { background: rgba(244, 102, 102, 0.06); border-color: rgba(244, 102, 102, 0.35); }
.sync-panel-amber  { background: rgba(214, 160, 43, 0.06);  border-color: rgba(214, 160, 43, 0.35); }
.sync-panel-blue   { background: var(--accent-faint);        border-color: var(--accent-mid); }
body.theme-light .sync-panel-red    { background: rgba(196, 50, 50, 0.05);  border-color: rgba(196, 50, 50, 0.30); }
body.theme-light .sync-panel-amber  { background: rgba(184, 130, 20, 0.05); border-color: rgba(184, 130, 20, 0.30); }
.sync-panel-head { display: flex; align-items: flex-start; gap: 12px; }
.sync-panel-icon { font-size: 20px; line-height: 1; padding-top: 1px; }
.sync-panel-titles { flex: 1; min-width: 0; }
.sync-panel-title    { font-weight: 700; font-size: 14px; color: var(--text); }
.sync-panel-subtitle { color: var(--muted); font-size: 12px; margin-top: 2px; }
.sync-panel-body { margin-top: 10px; padding-left: 32px; }
.sync-panel-section { margin-top: 4px; }
.sync-panel-section strong { color: var(--text); margin-right: 4px; }
.sync-panel-accts { margin-top: 12px; padding: 10px 12px; border-radius: 6px;
  background: rgba(255, 255, 255, 0.03); border: 1px solid var(--border); margin-left: 32px; }
body.theme-light .sync-panel-accts { background: rgba(0, 0, 0, 0.025); }
.sync-panel-accts-title { font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--muted); margin-bottom: 6px; font-weight: 600; }
.sync-panel-acct-row { display: flex; align-items: baseline; gap: 8px; padding: 3px 0;
  border-bottom: 1px dotted var(--border); }
.sync-panel-acct-row:last-child { border-bottom: 0; }
.sync-panel-acct-why { color: var(--muted); font-size: 12px; margin-left: auto;
  font-style: italic; }
.sync-panel-raw { margin-top: 12px; margin-left: 32px; }
.sync-panel-raw summary { cursor: pointer; color: var(--muted); font-size: 12px;
  user-select: none; }
.sync-panel-raw summary:hover { color: var(--text); }
.sync-panel-raw pre { margin-top: 8px; padding: 10px 12px; border-radius: 6px;
  background: var(--surface-2); border: 1px solid var(--border); font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px; overflow-x: auto; color: var(--text); white-space: pre-wrap; word-break: break-word; }
@media (max-width: 600px) {
  .sync-panel-body, .sync-panel-accts, .sync-panel-raw { padding-left: 0; margin-left: 0; }
  .sync-panel-acct-row { flex-direction: column; gap: 2px; }
  .sync-panel-acct-why { margin-left: 0; }
}

/* Warning banner — surfaces on drill pages when displayed data doesn't match source-of-truth
   (e.g. sum-of-adset-spend ≠ campaign-level spend due to stale sync). */
.banner-warn {
  background: var(--amber-soft);
  border: 1px solid var(--amber-mid);
  color: var(--text);
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 12.5px;
  line-height: 1.5;
  margin: 0 0 12px 0;
}
.banner-warn strong { color: var(--amber-strong); }
.banner-warn em { color: var(--red-strong); font-style: normal; font-weight: 500; }

/* ===========================================================================
   Key-value list (Health card, settings inspectors, etc.) — replaces raw JSON
   dumps with a scannable two-column layout.
   =========================================================================== */
.kv-grid {
  margin: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
}
.kv-row {
  display: grid;
  grid-template-columns: minmax(140px, max-content) 1fr;
  gap: 14px;
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
  font-size: 12.5px;
}
.kv-row:last-child { border-bottom: none; }
.kv-row dt {
  color: var(--muted);
  font-weight: 500;
  font-size: 11.5px;
  letter-spacing: 0.02em;
}
.kv-row dd {
  margin: 0;
  color: var(--text);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
  word-break: break-all;
  font-size: 12px;
}

/* ===========================================================================
   Modal (modal.js) — shared <dialog> replacing window.prompt/alert/confirm.
   =========================================================================== */
.grv-modal {
  border: none;
  background: transparent;
  padding: 0;
  max-width: 92vw;
  width: 460px;
}
.grv-modal::backdrop {
  background: rgba(8, 12, 18, 0.55);
  backdrop-filter: blur(2px);
}
body.theme-light .grv-modal::backdrop { background: rgba(20, 30, 50, 0.32); }
.grv-modal-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-pop);
  overflow: hidden;
  color: var(--text);
}
.grv-modal-head {
  padding: 16px 20px 6px;
}
.grv-modal-head h2 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.1px;
  color: var(--text);
}
.grv-modal-body {
  padding: 6px 20px 14px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--text);
}
.grv-modal-body strong { color: var(--text); }
.grv-modal-body em { color: var(--amber-strong); font-style: normal; font-weight: 600; }
.grv-modal-input-wrap {
  padding: 0 20px 14px;
}
.grv-modal-label {
  display: block;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--muted);
  margin-bottom: 6px;
}
.grv-modal-input {
  /* !important to override the global `input[type=number] { width: 56px }` rule above —
     otherwise number inputs render absurdly narrow inside the modal and clip values like
     "4000" down to "400". */
  width: 100% !important;
  min-width: 0;
  font-size: 14px;
  padding: 8px 12px;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 7px;
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  box-sizing: border-box;
}
.grv-modal-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
/* Hide the native number spinners — they add visual noise in dense forms and the user
   can type the value directly. */
.grv-modal-input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
.grv-modal-input[type="number"]::-webkit-outer-spin-button,
.grv-modal-input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
/* Currency-prefix wrapper: position the symbol inside the input gutter so the value
   reads as e.g. "₹ 4000" with the symbol fixed and the user typing the number. */
.grv-modal-input-prefix-wrap { position: relative; }
.grv-modal-input-prefix {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--muted);
  font-size: 14px;
  font-weight: 600;
  pointer-events: none;
  font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, sans-serif;
}
.grv-modal-input-prefix-wrap .grv-modal-input { padding-left: 28px; }
.grv-modal-err {
  margin-top: 6px;
  font-size: 12px;
  color: var(--red-strong);
}
.grv-modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 20px 16px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
}
.grv-modal-btn {
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 7px 16px;
  border-radius: 7px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background 80ms ease, border-color 80ms ease;
}
.grv-modal-btn--ghost {
  background: transparent;
  color: var(--muted);
  border-color: var(--border);
}
.grv-modal-btn--ghost:hover { background: var(--surface-3); color: var(--text); }
.grv-modal-btn--primary {
  background: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
  border-color: var(--btn-primary-bg);
}
.grv-modal-btn--primary:hover { background: var(--btn-primary-bg-hover); border-color: var(--btn-primary-bg-hover); }
.grv-modal-btn--warn {
  background: var(--amber);
  color: #fff;
  border-color: var(--amber);
}
.grv-modal-btn--warn:hover { filter: brightness(1.08); }
.grv-modal-btn--danger {
  background: var(--red);
  color: #fff;
  border-color: var(--red);
}
.grv-modal-btn--danger:hover { filter: brightness(1.08); }

/* ===========================================================================
   Kill list — "find losers" query builder (Real Attribution → Kill list).
   Inline grid of label+input controls + saved-preset chips.
   =========================================================================== */
.kl-builder {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  padding: 6px 0 4px;
  align-items: end;
}
.kl-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.kl-field > label {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--muted); font-weight: 600;
}
.kl-field select, .kl-field input[type="number"], .kl-field input[type="text"] {
  width: 100%;
  font-size: 13px;
  padding: 7px 10px;
  /* `background-color` (not shorthand `background:`) so we don't reset the
     base select's chevron background-image + background-repeat: no-repeat. */
  background-color: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.kl-field.kl-num input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
.kl-field.kl-num input[type="number"]::-webkit-outer-spin-button,
.kl-field.kl-num input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
/* Currency-prefix input wrapper — ₹ sits inside the input gutter so the user types just the number */
.kl-input-prefix { position: relative; }
.kl-input-prefix > span {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  color: var(--muted); font-weight: 600; font-size: 13px; pointer-events: none;
}
.kl-input-prefix input { padding-left: 22px !important; }
.kl-field.kl-toggle { align-self: flex-end; padding-bottom: 6px; }
.kl-checkbox {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 13px; cursor: pointer; color: var(--text);
}
.kl-checkbox input { width: 15px; height: 15px; }
.kl-field.kl-actions { display: flex; flex-direction: row; gap: 6px; align-items: end; }
.kl-field.kl-actions .btn-primary {
  background: var(--btn-primary-bg); color: var(--btn-primary-fg); border: 1px solid var(--btn-primary-bg);
  padding: 7px 16px; border-radius: 6px; font-weight: 600; cursor: pointer; font-size: 13px;
  font-family: inherit;
}
.kl-field.kl-actions .btn-primary:hover { background: var(--btn-primary-bg-hover); border-color: var(--btn-primary-bg-hover); }
.kl-field.kl-actions .btn-primary:disabled { opacity: 0.55; cursor: not-allowed; }
.kl-presets {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.kl-preset {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent-mid);
  padding: 4px 10px; border-radius: 99px; font-size: 12px; font-weight: 500;
  cursor: pointer; font-family: inherit;
}
.kl-preset:hover { background: var(--accent-mid); }
.kl-preset-x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 50%;
  font-size: 12px; line-height: 1; color: var(--muted);
  margin-left: 2px;
}
.kl-preset-x:hover { background: var(--red-soft); color: var(--red); }
.kl-name-link { color: var(--accent); text-decoration: none; }
.kl-name-link:hover { color: var(--accent-2); text-decoration: underline; }

/* ===========================================================================
   Viewer-role suppression — hide write-only affordances for read-only users so
   they don't see checkboxes / edit buttons that 403 on click. Set on <body>
   by loadCurrentUser() in app.js.
   =========================================================================== */
body.role-viewer .col-with-check input[type="checkbox"],
body.role-viewer .dt-master-check,
body.role-viewer .dt-row-check { display: none !important; }
body.role-viewer .ra-budget-edit,
body.role-viewer .ras-budget-edit,
body.role-viewer .ra-camp-toggle,
body.role-viewer .ras-status-toggle,
body.role-viewer .ras-ad-status-toggle { display: none !important; }
/* Restore normal left-padding when the checkbox column is collapsed for viewers */
body.role-viewer .dt-table.dt-selectable .dt-td-with-check,
body.role-viewer .dt-table.dt-selectable .dt-th-with-check,
body.role-viewer .data-table .col-with-check { padding-left: 9px !important; }

/* ===========================================================================
   Capability suppression (multi-store RBAC). Body gets `cap-write` / `cap-manage`
   from /api/auth/me's active_store.can (set by loadCurrentUser). Controls tagged
   `.requires-manage` (grant BM write-access, connection + sync/FX settings,
   Fship connect/disconnect, automations) are hidden from anyone without MANAGE
   on the active store — i.e. media-buyers + viewers — so they aren't shown
   buttons that 403 on click. `.requires-write` is the same for write-tier
   actions. Owner/admin/manager keep cap-manage; media-buyer keeps cap-write.
   =========================================================================== */
body:not(.cap-manage) .requires-manage { display: none !important; }
body:not(.cap-write) .requires-write { display: none !important; }

/* ===========================================================================
   Creatives grid (Real Attribution → Creatives) — Pinterest-style thumbnail
   browser with metric overlay per card.
   =========================================================================== */
.creative-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 14px;
  padding: 6px 2px 2px;
}
.creative-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: border-color 80ms ease, transform 80ms ease;
  /* Perf: skip layout/paint for off-screen cards (5-10x faster initial render
     on 500+ card grids). `contain-intrinsic-size` reserves space so scrollbars
     stay accurate before the card has been painted. Safe degradation: browsers
     that don't support content-visibility (Safari <18) just ignore both props
     and render the card normally. */
  content-visibility: auto;
  contain-intrinsic-size: 360px 320px;
}
.creative-card:hover { border-color: var(--accent); }
/* Every card is clickable (opens the preview modal), so cursor + lift on hover
   apply to all of them now — not just rows with an adset_id. */
.creative-card { cursor: pointer; }
.creative-card:hover { transform: translateY(-1px); }
.cr-thumb {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  background: linear-gradient(135deg, var(--surface-2), var(--surface-3));
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.cr-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.cr-thumb-fallback {
  position: absolute; inset: 0;
  display: none;       /* hidden by default; shown only when there's no <img> or when img errors */
  align-items: center; justify-content: center;
  font-size: 56px; opacity: 0.25;
  pointer-events: none;
}
/* No <img> child at all = show fallback (creative has no thumbnail URL synced) */
.cr-thumb:not(:has(img)) .cr-thumb-fallback { display: flex; }
/* Image failed to load (onerror handler adds this class) = show fallback */
.cr-thumb.cr-thumb-broken .cr-thumb-fallback { display: flex; }
.cr-thumb-format {
  position: absolute; top: 8px; right: 8px;
  z-index: 2;
}
.cr-format-badge {
  display: inline-flex; align-items: center; gap: 4px;
  background: rgba(0, 0, 0, 0.65);
  color: white;
  font-size: 10px;
  font-weight: 600;
  padding: 3px 7px;
  border-radius: 99px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  backdrop-filter: blur(4px);
}
body.theme-light .cr-format-badge { background: rgba(20, 30, 50, 0.75); }
.cr-checkbox {
  position: absolute; top: 8px; left: 8px;
  z-index: 2;
  background: rgba(255, 255, 255, 0.92);
  border-radius: 4px;
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
}
.cr-checkbox input { width: 14px; height: 14px; margin: 0; cursor: pointer; }
.cr-card-body {
  padding: 10px 12px 12px;
  display: flex; flex-direction: column; gap: 8px;
  flex: 1;
}
.cr-title {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 34px;
}
.cr-card-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  font-size: 10.5px;
  color: var(--muted);
}
.cr-account-name {
  font-size: 10.5px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cr-badge {
  display: inline-flex; align-items: center;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--accent-mid);
  font-size: 10px;
  font-weight: 600;
  padding: 1px 6px;
  border-radius: 99px;
}
.cr-badge-accounts { background: var(--accent-soft); color: var(--accent); }
.cr-badge-ads { background: var(--surface-3); color: var(--muted); border-color: var(--border); }
.cr-card-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 10px;
  font-size: 11.5px;
}
.cr-stat {
  display: flex; justify-content: space-between; align-items: baseline;
}
.cr-stat-label {
  color: var(--muted);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.cr-stat-val {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.cr-stat-primary { color: var(--accent); font-weight: 700; }
.cr-stat-good { color: var(--green-strong); font-weight: 700; }
.cr-stat-warn { color: var(--amber-strong); font-weight: 700; }
.cr-stat-bad  { color: var(--red-strong); font-weight: 700; }
.cr-na { color: var(--muted-2); }

/* =====================================================================
   Creative preview modal — opens on card click, shows Meta's ad preview
   iframe + key stats sidebar. Custom overlay (not <dialog>) so we can
   control the side-by-side layout and the iframe sizing per ad_format.
   ===================================================================== */
.cr-modal {
  position: fixed; inset: 0;
  z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.cr-modal[hidden] { display: none; }
.cr-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(8, 12, 20, 0.75);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  cursor: pointer;
}
body.theme-light .cr-modal-backdrop { background: rgba(40, 60, 90, 0.45); }
.cr-modal-content {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
  max-width: 1080px; width: 100%;
  max-height: calc(100vh - 40px);
  overflow: hidden;
  display: flex; flex-direction: column;
}
.cr-modal-close {
  position: absolute; top: 12px; right: 12px;
  z-index: 2;
  width: 32px; height: 32px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 50%;
  color: var(--text);
  font-size: 20px; line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  padding: 0;
}
.cr-modal-close:hover { background: var(--surface-3); border-color: var(--border-strong); }
.cr-modal-grid {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 0;
  flex: 1; min-height: 0;
}
.cr-modal-left {
  display: flex; flex-direction: column;
  background: var(--surface-2);
  border-right: 1px solid var(--border);
  min-width: 0;
  padding: 16px;
  gap: 12px;
}
.cr-modal-formats {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding-right: 40px;  /* leave room for close button */
}
.cr-fmt-btn {
  font-size: 11px;
  padding: 5px 10px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  transition: all 0.15s ease;
}
.cr-fmt-btn:hover { color: var(--text); border-color: var(--border-strong); }
.cr-fmt-btn.cr-fmt-active {
  background: var(--btn-primary-bg);
  border-color: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
}
body.theme-light .cr-fmt-btn.cr-fmt-active { color: var(--btn-primary-fg); }
.cr-modal-iframe-wrap {
  flex: 1; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  background: #000;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
  /* default size (horizontal-ish — feed format). Vertical formats override below. */
  min-height: 520px;
}
.cr-modal-iframe {
  /* Width/height are set inline by JS using Meta's reported dimensions
     (with sane min/max clamps) — see fetchAndRenderPreview() in realattr.js. */
  border: 0;
  background: #fff;
  display: block;
}
.cr-modal-loading, .cr-modal-error {
  color: var(--muted);
  font-size: 13px;
  text-align: center;
  padding: 24px;
  max-width: 320px;
}
.cr-modal-error { color: var(--amber-strong); }
.cr-modal-right {
  display: flex; flex-direction: column;
  padding: 44px 16px 16px 16px;  /* top padding leaves room for close button line */
  gap: 12px;
  overflow-y: auto;
  background: var(--surface);
  min-width: 0;
}
.cr-modal-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.4;
  /* clamp to 4 lines max — long captions get truncated with ellipsis */
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.cr-modal-meta {
  font-size: 11px;
  display: flex; flex-direction: column; gap: 4px;
}
.cr-modal-meta .badge { font-size: 9px; padding: 1px 6px; }
.cr-modal-stat-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}
.cr-modal-stat-table td {
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
}
.cr-modal-stat-table td:first-child { color: var(--muted); }
.cr-modal-stat-table td:last-child { text-align: right; color: var(--text); }
.cr-modal-stat-table tr:last-child td { border-bottom: 0; }
.cr-modal-actions {
  display: flex; flex-direction: column; gap: 8px;
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.cr-modal-btn {
  display: block;
  text-align: center;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 500;
  text-decoration: none;
}

/* Narrow screens: stack iframe + sidebar */
@media (max-width: 760px) {
  .cr-modal { padding: 8px; }
  .cr-modal-content { max-height: calc(100vh - 16px); }
  .cr-modal-grid { grid-template-columns: 1fr; }
  .cr-modal-left { border-right: 0; border-bottom: 1px solid var(--border); padding: 12px; }
  .cr-modal-right { padding: 12px; }
  .cr-modal-iframe-wrap { min-height: 480px; }
  .cr-modal-iframe { width: 340px; height: 560px; }
  .cr-modal-iframe-wrap.cr-vertical .cr-modal-iframe { width: 320px; height: 560px; }
}

/* On narrow screens, single column */
@media (max-width: 600px) {
  .creative-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .creative-card .cr-card-stats { font-size: 11px; }
  .cr-title { font-size: 12px; min-height: 30px; }
}

/* Account-access editor inside the user-management modal */
.acc-acl-toggle { display: flex; align-items: center; gap: 8px; padding: 8px 0; font-size: 13px; cursor: pointer; }
.acc-acl-toggle input { width: 16px; height: 16px; cursor: pointer; }
.acc-acl-toolbar { display: flex; gap: 6px; margin: 8px 0; align-items: center; }
.acc-acl-toolbar input { flex: 1; }
.acc-acl-list {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-2);
  max-height: 320px;
  overflow-y: auto;
  padding: 4px;
}
.acc-acl-row {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 8px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12.5px;
}
.acc-acl-row:hover { background: var(--row-hover); }
.acc-acl-row input { width: 15px; height: 15px; flex-shrink: 0; cursor: pointer; }
.acc-acl-name { font-weight: 500; color: var(--text); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acc-acl-meta { color: var(--muted); font-size: 11px; }

/* ===========================================================================
   Skeleton loaders — animated placeholder bars while data fetches.
   Use .skeleton on any block; .skeleton-line / .skeleton-card for shapes.
   =========================================================================== */
@keyframes skel-shimmer {
  0%   { background-position: -200px 0; }
  100% { background-position: calc(200px + 100%) 0; }
}
.skeleton {
  background-color: var(--surface-2);
  background-image: linear-gradient(90deg,
    var(--surface-2) 0%,
    var(--surface-3) 50%,
    var(--surface-2) 100%);
  background-size: 200px 100%;
  background-repeat: no-repeat;
  border-radius: 6px;
  animation: skel-shimmer 1.2s ease-in-out infinite;
  color: transparent;
  user-select: none;
  pointer-events: none;
}
.skeleton-line { height: 12px; margin: 6px 0; }
.skeleton-line.lg { height: 20px; }
.skeleton-line.xl { height: 28px; }
.skeleton-line.short { width: 40%; }
.skeleton-line.med   { width: 65%; }
.skeleton-kpi { height: 60px; border-radius: 10px; margin: 0; }
.skeleton-table-row {
  display: flex;
  gap: 12px;
  padding: 10px 8px;
  border-bottom: 1px solid var(--border);
}
.skeleton-table-row > .skeleton { flex: 1; height: 14px; }

/* ===========================================================================
   Date Range Picker (datepicker.js) — modern range picker replacing the old
   preset-row + native <input type="date"> pair in the topbar.
   =========================================================================== */
.drp-trigger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 6px 12px;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 12.5px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: border-color 80ms ease, background 80ms ease;
  min-width: 230px;
}
.drp-trigger:hover { border-color: var(--accent); background: var(--surface-3); }
.drp-trigger[aria-expanded="true"] { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.drp-trigger .drp-icon { font-size: 13px; line-height: 1; }
.drp-trigger .drp-label { flex: 1; text-align: left; color: var(--text); }
.drp-trigger .drp-hint { font-size: 11px; color: var(--muted); padding: 2px 7px; background: var(--surface); border-radius: 9px; border: 1px solid var(--border); }
.drp-trigger .drp-chev { color: var(--muted); font-size: 10px; transition: transform 120ms ease; }
.drp-trigger[aria-expanded="true"] .drp-chev { transform: rotate(180deg); color: var(--accent); }

/* Popover */
.drp-popover {
  position: fixed;
  width: 720px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: var(--shadow-pop);
  z-index: 1000;
  display: grid;
  grid-template-columns: 200px 1fr;
  overflow: hidden;
  font-size: 12.5px;
  color: var(--text);
  animation: drp-fade-in 100ms ease-out;
}
@keyframes drp-fade-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }

/* Presets column */
.drp-presets {
  background: var(--surface-2);
  border-right: 1px solid var(--border);
  padding: 8px 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
  max-height: 400px;
  overflow-y: auto;
}
.drp-preset {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 8px 12px;
  background: transparent;
  border: 0;
  border-left: 2px solid transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  text-align: left;
  transition: background 60ms ease;
}
.drp-preset:hover { background: var(--surface-3); }
.drp-preset.active {
  background: var(--accent-soft);
  border-left-color: var(--accent);
  color: var(--accent);
}
.drp-preset-label { font-weight: 600; }
.drp-preset-range { font-size: 10.5px; color: var(--muted); font-weight: 400; }
.drp-preset.active .drp-preset-range { color: var(--accent-2); }

/* Calendars + footer */
.drp-cals {
  display: flex;
  flex-direction: column;
  background: var(--surface);
}
.drp-cal-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--border);
  padding: 0;
}
.drp-cal {
  background: var(--surface);
  padding: 12px 14px 8px;
}
.drp-cal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.drp-cal-title {
  flex: 1;
  text-align: center;
  font-weight: 600;
  color: var(--text);
  font-size: 13px;
}
.drp-nav, .drp-nav-spacer {
  width: 24px; height: 24px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent;
  border: 0;
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  border-radius: 4px;
  cursor: pointer;
}
.drp-nav:hover { background: var(--surface-2); color: var(--accent); }
.drp-cal-dow {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  margin-bottom: 4px;
}
.drp-dow {
  text-align: center;
  font-size: 10.5px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 4px 0;
}
.drp-cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
}
.drp-day {
  height: 28px;
  background: transparent;
  border: 0;
  color: var(--text);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  border-radius: 4px;
  position: relative;
  padding: 0;
  transition: background 60ms ease;
}
.drp-day-blank { cursor: default; }
.drp-day:not(.drp-day-blank):hover {
  background: var(--surface-2);
}
.drp-day-today {
  font-weight: 700;
  box-shadow: inset 0 0 0 1px var(--accent);
  color: var(--accent);
}
.drp-day-in-range {
  background: var(--accent-soft);
  border-radius: 0;
  color: var(--accent);
}
.drp-day-range-start {
  background: var(--accent);
  color: #fff;
  border-radius: 4px 0 0 4px;
}
.drp-day-range-end {
  background: var(--accent);
  color: #fff;
  border-radius: 0 4px 4px 0;
}
.drp-day-range-start.drp-day-range-end {
  border-radius: 4px;
}
.drp-day-today.drp-day-range-start,
.drp-day-today.drp-day-range-end { color: #fff; box-shadow: none; }
.drp-day-today.drp-day-in-range:not(.drp-day-range-start):not(.drp-day-range-end) { color: var(--accent); }

/* Footer */
.drp-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
}
.drp-range-display {
  display: flex;
  align-items: center;
  gap: 14px;
}
.drp-range-side { display: flex; flex-direction: column; gap: 1px; }
.drp-range-label { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.drp-range-value { font-weight: 600; color: var(--text); font-size: 12.5px; }
.drp-range-arrow { color: var(--muted); font-size: 14px; }
.drp-range-count {
  margin-left: 6px;
  padding: 3px 9px;
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 10px;
  font-size: 11px;
  font-weight: 600;
}
.drp-actions { display: flex; gap: 8px; }
.drp-btn {
  padding: 6px 14px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
}
.drp-btn:hover { background: var(--surface-3); border-color: var(--accent); color: var(--accent); }
.drp-btn.drp-apply {
  background: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
  border-color: var(--btn-primary-bg);
}
.drp-btn.drp-apply:hover { background: var(--btn-primary-bg-hover); border-color: var(--btn-primary-bg-hover); color: var(--btn-primary-fg); }
.drp-btn:disabled { opacity: 0.5; cursor: default; background: var(--surface-2); color: var(--muted); border-color: var(--border); }

/* Responsive — stack the two calendars vertically on small screens. JS at
   datepicker.js positionPopover() detects this same ≤720 breakpoint and
   anchors the panel at top-left (8px,8px) instead of doing trigger-anchored
   math against a 720px reference width — earlier the math under-shot and
   pushed the panel off the left edge. CSS adds max-height + overflow-y so
   the stacked content (presets row + 2 calendars + footer) scrolls inside
   the viewport instead of clipping. */
@media (max-width: 720px) {
  .drp-popover {
    width: calc(100vw - 16px);
    max-height: calc(100vh - 16px);
    overflow-y: auto;
    grid-template-columns: 1fr;
  }
  .drp-presets { max-height: 160px; flex-direction: row; flex-wrap: wrap; padding: 8px; }
  .drp-preset { border-left: 0; border-bottom: 2px solid transparent; min-width: 100px; }
  .drp-preset.active { border-bottom-color: var(--accent); border-left-color: transparent; }
  .drp-cal-row { grid-template-columns: 1fr; }
}

/* ===========================================================================
   Universal table toolbar — search + quick filter chips above every table.
   =========================================================================== */
.table-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  flex-wrap: wrap;
}
.tt-search {
  flex: 0 0 240px;
  /* Inherits global input styling — themed automatically */
}
.tt-chips {
  display: inline-flex;
  gap: 4px;
  flex-wrap: wrap;
}
.filter-chip {
  padding: 4px 10px;
  background: var(--surface-2);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 14px;
  font-size: 11.5px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background 60ms ease, color 60ms ease, border-color 60ms ease;
}
.filter-chip:hover {
  background: var(--surface-3);
  color: var(--text);
}
.filter-chip.active {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: var(--accent);
}
.tt-count { margin-left: auto; font-size: 11.5px; }
.tt-right { display: inline-flex; gap: 6px; align-items: center; }

/* tk-col-chip: pill-button used in the toolbar's right slot to show/hide
   secondary columns (Notion / Airtable pattern). Visually matches .filter-chip
   but lives outside the chip-handler so the toolbar wirer won't treat it as a
   row predicate. Active state = columns are revealed. */
.tk-col-chip {
  padding: 4px 10px;
  background: var(--surface-2);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 14px;
  font-size: 11.5px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background 60ms ease, color 60ms ease, border-color 60ms ease;
}
.tk-col-chip:hover { background: var(--surface-3); color: var(--text); }
.tk-col-chip.active {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: var(--accent);
}
/* Column hiding for the Google · Accounts performance table.
   .col-extra is applied to both <th> and matching <td> cells; the table-level
   class hides them. Single rule = no per-column toggling needed. */
.g-acctperf-cols-hide-extras .col-extra { display: none; }

/* ===========================================================================
   Bulk-select on DataTable — checkbox column + selected-row highlight
   + floating action bar that appears when N rows are selected.
   =========================================================================== */
/* Bulk-select — checkbox is absolute-positioned INSIDE the first content cell.
   No separate column = zero impact on table layout. The first cell gets a little
   left-padding to make room for the checkbox visually.
   This matches the pattern used by Stripe / Linear / Vercel / Notion. */
.dt-table.dt-selectable .dt-td-with-check,
.dt-table.dt-selectable .dt-th-with-check,
.data-table tbody td.col-with-check,
.data-table thead th.col-with-check {
  position: relative;
  padding-left: 26px !important;
}
.dt-master-check, .dt-row-check,
.ras-master-check, .ras-row-check,
.ads-master-check, .ads-row-check {
  position: absolute;
  left: 7px;
  top: 50%;
  transform: translateY(-50%);
  width: 13px;
  height: 13px;
  margin: 0;
  padding: 0;
  cursor: pointer;
  accent-color: var(--accent);
}
.dt-row-selected td,
.data-table tr.row-selected td {
  background: var(--accent-soft) !important;
}
.dt-row-selected:hover td { background: var(--accent-mid) !important; }

/* Floating bulk-action bar — appears at bottom of viewport when N > 0 selected */
.bulk-action-bar {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 14px 10px 18px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: var(--shadow-pop);
  z-index: 800;
  font-size: 13px;
  animation: bulk-bar-rise 140ms ease-out;
}
@keyframes bulk-bar-rise { from { opacity: 0; transform: translate(-50%, 12px); } to { opacity: 1; transform: translate(-50%, 0); } }
/* UX: when the bulk-action bar is showing, reserve space at the bottom of the
   page so it doesn't cover the totals row of the table. Without this, users
   select 30 campaigns to bulk-pause and lose sight of the combined-spend
   total they were trying to verify against. */
body:has(.bulk-action-bar) { padding-bottom: 100px; }
.bulk-bar-count {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 16px;
  font-weight: 600;
  font-size: 12.5px;
}
.bulk-bar-meta {
  color: var(--muted);
  font-size: 11.5px;
}
.bulk-bar-actions { display: flex; gap: 6px; align-items: center; }
.bulk-bar-btn {
  padding: 6px 14px;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 7px;
  font-size: 12px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
}
.bulk-bar-btn:hover { background: var(--surface-3); border-color: var(--accent); color: var(--accent); }
.bulk-bar-btn.bulk-bar-btn-primary {
  background: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
  border-color: var(--btn-primary-bg);
}
.bulk-bar-btn.bulk-bar-btn-primary:hover { background: var(--btn-primary-bg-hover); border-color: var(--btn-primary-bg-hover); }
.bulk-bar-btn.bulk-bar-btn-danger {
  background: var(--red);
  color: #fff;
  border-color: var(--red);
}
.bulk-bar-btn.bulk-bar-btn-danger:hover { background: var(--red-strong); border-color: var(--red-strong); }
.bulk-bar-btn:disabled { opacity: 0.55; cursor: wait; }
.bulk-bar-close {
  background: transparent;
  border: 0;
  color: var(--muted);
  font-size: 18px;
  padding: 2px 6px;
  cursor: pointer;
  margin-left: 4px;
}
.bulk-bar-close:hover { color: var(--text); }
.bulk-bar-progress {
  margin-left: 8px;
  font-size: 11.5px;
  color: var(--muted);
}

/* Backfill progress bar on Sync & Settings */
.bf-progress { padding: 0 16px 12px; }
.bf-bar-track {
  width: 100%;
  height: 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  overflow: hidden;
}
.bf-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  border-radius: 5px;
  transition: width 0.4s ease;
}

/* Sidebar user widget (bottom of sidebar) */
.sidebar-user {
  padding: 10px 16px 14px;
  border-top: 1px solid var(--border);
  margin-top: auto;
  font-size: 12px;
}
.su-name {
  font-weight: 600;
  color: var(--text);
  margin-bottom: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.su-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
}
.su-meta a { color: var(--muted); font-size: 11px; }
.su-meta a:hover { color: var(--accent); }

/* Sidebar nav layout — push user widget to bottom */
.sidebar {
  display: flex;
  flex-direction: column;
}
.nav { flex: 1; }

/* Account multi-select filter */
.acct-filter {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 12px;
  margin-bottom: 8px;
  font-size: 12.5px;
  max-width: 460px;
}
.acct-filter summary {
  cursor: pointer;
  user-select: none;
  list-style: none;
  color: var(--text);
}
.acct-filter summary::-webkit-details-marker { display: none; }
.acct-filter summary::before { content: '▸'; margin-right: 6px; color: var(--muted); transition: transform 0.15s ease; display: inline-block; }
.acct-filter[open] summary::before { transform: rotate(90deg); }
.acct-filter-body {
  padding: 10px 0 6px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 4px 16px;
  max-height: 280px;
  overflow-y: auto;
}
.acct-filter-row {
  grid-column: 1 / -1;
  display: flex;
  gap: 8px;
  align-items: center;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}
.acct-filter-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  padding: 3px 0;
  cursor: pointer;
}
.acct-filter-item:hover { color: var(--accent-2); }
#ra-acct-summary { color: var(--accent-2); font-weight: 600; }

/* =========================================================================
   Generic DataTable component
   ========================================================================= */
.dt-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  flex-wrap: wrap;
}
/* Quick filter chips inside the DataTable toolbar */
.dt-chips { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.dt-chip {
  padding: 3px 9px;
  background: var(--surface-2);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 12px;
  font-size: 11.5px;
  font-weight: 500;
  cursor: pointer;
  transition: background 60ms ease, color 60ms ease, border-color 60ms ease;
  font-family: inherit;
}
.dt-chip:hover { background: var(--surface-3); color: var(--text); }
.dt-chip.active { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); }

/* Saved-views dropdown — sits next to ⚙ Columns. */
.dt-view-wrap { position: relative; }
.dt-view-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
}
.dt-view-btn:hover { background: var(--surface-3); border-color: var(--accent); color: var(--accent); }
.dt-view-icon { font-size: 12px; }
.dt-view-chev { font-size: 9px; color: var(--muted); margin-left: 2px; }
.dt-view-name { max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dt-view-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 240px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  box-shadow: var(--shadow-pop);
  z-index: 60;
  overflow: hidden;
}
.dt-view-head {
  padding: 8px 12px;
  font-size: 10.5px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.dt-view-list { list-style: none; padding: 4px 0; margin: 0; max-height: 280px; overflow-y: auto; }
.dt-view-item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 12px;
  cursor: pointer;
  font-size: 12.5px;
  color: var(--text);
}
.dt-view-item:hover { background: var(--surface-2); }
.dt-view-item.active { background: var(--accent-soft); color: var(--accent); font-weight: 500; }
.dt-view-mark { width: 14px; color: var(--accent); }
.dt-view-del {
  margin-left: auto;
  background: transparent;
  border: 0;
  color: var(--muted);
  font-size: 11px;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 4px;
}
.dt-view-del:hover { background: var(--red-soft); color: var(--red-strong); }
.dt-view-actions { padding: 6px; border-top: 1px solid var(--border); background: var(--surface-2); }
.dt-view-save {
  width: 100%;
  padding: 6px;
  background: transparent;
  color: var(--accent);
  border: 0;
  font-size: 12px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  border-radius: 4px;
}
.dt-view-save:hover { background: var(--accent-soft); }
.dt-search {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 6px 10px;
  border-radius: 6px;
  font-size: 12.5px;
  width: 240px;
}
.dt-row-count { margin-left: auto; font-size: 12px; color: var(--muted); }

.dt-gear-wrap { position: relative; }
.dt-gear-btn {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 5px 12px;
  font-size: 12px;
  border-radius: 6px;
  cursor: pointer;
}
.dt-gear-btn:hover { background: var(--surface-3); }
.dt-gear-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow-pop);
  padding: 8px;
  min-width: 280px;
  max-height: 480px;
  overflow-y: auto;
  z-index: 50;
}
.dt-gear-head {
  font-size: 11px;
  color: var(--muted);
  padding: 4px 8px 8px;
  border-bottom: 1px solid var(--border);
}
.dt-col-list {
  list-style: none;
  padding: 0;
  margin: 6px 0;
}
.dt-col-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 4px;
  cursor: grab;
  font-size: 12.5px;
}
.dt-col-item:hover { background: var(--surface-2); }
.dt-col-item.dt-dragging { opacity: 0.4; }
.dt-col-item input { margin: 0; }
.dt-col-item span { flex: 1; }
.dt-drag-handle { color: var(--muted); cursor: grab; font-size: 12px; }
.dt-gear-actions { padding: 8px 4px 4px; border-top: 1px solid var(--border); }
.dt-reset {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 4px 10px;
  border-radius: 4px;
  font-size: 11px;
  cursor: pointer;
}

.dt-scroll { overflow-x: auto; }
.dt-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;            /* tighter than 12.5 — matches the clean .data-table tight look */
}
.dt-table th, .dt-table td {
  padding: 5px 9px;           /* was 6px 10px */
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: middle;
}
.dt-table td { line-height: 1.35; }
.dt-table th.num, .dt-table td.num {
  text-align: right;
  white-space: nowrap;        /* numbers never wrap */
}
.dt-table td .hint.mono { line-height: 1.2; font-size: 10.5px; }
.dt-table .badge { white-space: nowrap; }
.dt-th {
  background: var(--surface-2);
  font-weight: 600;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  cursor: pointer;
  user-select: none;
  position: sticky;
  top: 0; /* sticks to top of its scroll context — works inside .dt-scroll / page-level alike */
  z-index: 5;
  /* Hairline shadow that becomes visible only when content is scrolled under
     the header — Stripe Dashboard / Linear list pattern. Without this, the
     sticky header blends into the rows behind it. */
  box-shadow: inset 0 -1px 0 var(--border);
  white-space: nowrap;        /* headers in ONE line — no "Meta\npur." wrapping */
}
.dt-th:hover { background: var(--surface-3); }
.dt-th:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.dt-th-active { color: var(--accent-2); }
.dt-th-label { display: inline-block; }
.dt-sort-arrow { color: var(--accent); margin-left: 4px; font-size: 10px; }
.dt-row:hover { background: var(--row-hover); }
.dt-row-clickable { cursor: pointer; }
.dt-row-synthetic td {
  font-style: italic;
  color: var(--muted);
  background: var(--synthetic-tint);
}
/* Inline action buttons (Pause / Activate) — hidden by default, visible on row hover so
   the table stays clean and dense like the Ad Accounts / Product drill tables.
   UX: only hide-then-hover on devices that actually support hover. On touch
   devices (iPad / phone) there's no hover state, so we keep them visible —
   otherwise admins on tablets literally couldn't see (let alone tap) Pause. */
@media (hover: hover) {
  .dt-row .btn-tiny { opacity: 0; transition: opacity 0.1s ease; }
  .dt-row:hover .btn-tiny { opacity: 1; }
}
.dt-empty { padding: 24px; text-align: center; color: var(--muted); }
.dt-totals-row td {
  background: var(--surface-2);
  font-weight: 600;
  border-top: 2px solid var(--border-strong);
  white-space: nowrap;
}

/* Inline action button (Pause / Activate in tables) — admin-only */
.btn-tiny {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  padding: 1px 8px;
  border-radius: 4px;
  font-size: 10.5px;
  cursor: pointer;
  margin-left: 4px;
}
.btn-tiny:hover { background: var(--surface-3); border-color: var(--accent); color: var(--accent-2); }
.btn-tiny:disabled { opacity: 0.5; cursor: default; }

/* Name column (Campaign / Product / Adset) needs room for one-line names.
   Width can be overridden per-table via the .dt-narrow-first / .dt-wide-first modifiers
   on the table itself (configurable from DataTable options.firstColWidth). */
.dt-table th:first-child, .dt-table td:first-child {
  min-width: 260px;
  max-width: 380px;
}
.dt-table.dt-narrow-first th:first-child, .dt-table.dt-narrow-first td:first-child {
  min-width: 180px; max-width: 260px;
}
.dt-table.dt-wide-first th:first-child, .dt-table.dt-wide-first td:first-child {
  min-width: 320px; max-width: 520px;
}
.dt-table.dt-auto-first th:first-child, .dt-table.dt-auto-first td:first-child {
  min-width: 200px; max-width: none;
}
/* Anchor links inside cells stay inline */
.dt-table td a { color: var(--accent); }
.dt-table td a:hover { color: var(--accent-2); }

/* Adset table — hover-reveal inline action buttons (mirror DataTable behavior). */
/* Same touch-device exemption as .dt-row .btn-tiny — see comment above. */
@media (hover: hover) {
  .ras-row .btn-tiny { opacity: 0; transition: opacity 0.1s ease; }
  .ras-row:hover .btn-tiny { opacity: 1; }
}

/* ===========================================================================
   Row-expand chevron — inline tree-style expand-to-dates on Campaign / Adset
   tables. Mirrors the ClickFlare UX: click ▶ next to a row → daily breakdown
   rows appear directly beneath that row, indented and styled subtly.
   =========================================================================== */
.row-name-wrap {
  display: flex;
  align-items: center;
  gap: 6px;
}
.row-name-text { flex: 1; min-width: 0; }
.row-expand-chev {
  flex: 0 0 16px;
  width: 16px;
  height: 16px;
  padding: 0;
  font-size: 9px;
  line-height: 1;
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 3px;
  cursor: pointer;
  transition: color 80ms ease, background 80ms ease, transform 120ms ease;
}
.row-expand-chev:hover { color: var(--accent); background: var(--surface-2); }
.row-expand-chev.expanded { color: var(--accent); transform: rotate(0deg); }
.row-expand-chev:disabled { cursor: wait; }

/* Daily rows injected under a parent row */
tr.row-expand-child td {
  background: var(--accent-faint);
  border-top: 1px dashed var(--accent-mid);
  font-size: 11.5px;
}
tr.row-expand-child:hover td { background: var(--accent-soft); }
.day-indent {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding-left: 22px;     /* aligns with where the chevron sat in the parent */
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 500;
}
.day-indent::before {
  content: '└';
  color: var(--muted);
  font-size: 11px;
  margin-right: 2px;
}
.day-indent strong { color: var(--text); font-weight: 600; }

/* ===========================================================================
   Back-to-parent banner on every drill page. Pinned to the top of #page-root
   so it's always the first thing users see when entering a deep view.
   =========================================================================== */
.back-banner {
  margin: 0 0 12px 0;
}
.back-banner-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px 7px 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font-size: 12.5px;
  font-weight: 500;
  text-decoration: none;
  transition: background 80ms ease, border-color 80ms ease, transform 60ms ease;
}
.back-banner-btn:hover {
  background: var(--surface-3);
  border-color: var(--accent);
  color: var(--accent);
  text-decoration: none;
}
.back-banner-btn:active { transform: translateY(1px); }
.back-banner-btn .back-arrow {
  font-size: 16px;
  line-height: 1;
  color: var(--accent);
  font-weight: 700;
}

/* ===========================================================================
   Daily-breakdown card (inline under every drill page — Account / Campaign-Adsets
   / Product-Account). Summary stat strip + table with inline spend-trend bars.
   =========================================================================== */
.mdt-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 1px;
  background: var(--border);
  border-bottom: 1px solid var(--border);
  margin-bottom: 0;
}
.mdt-stat {
  background: var(--surface);
  padding: 12px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.mdt-stat-label {
  font-size: 10.5px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.mdt-stat-value {
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.2;
}
.mdt-stat-sub {
  font-size: 11px;
  color: var(--muted);
}
/* Inline spend-trend bar in the daily table — visual at-a-glance for which days spent the most */
.mdt-bar {
  width: 90px;
  height: 8px;
  background: var(--surface-2);
  border-radius: 3px;
  overflow: hidden;
  position: relative;
}
.mdt-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  border-radius: 3px;
  transition: width 0.2s ease;
}
.mdt-row-peak td { background: var(--accent-faint); }
.mdt-row-peak .mdt-bar-fill { background: linear-gradient(90deg, #f7b955, #e89224); }
.mdt-table { margin-top: 0; }

/* ===========================================================================
   Cmd+K Command Palette — Linear/Vercel/Notion-style universal jump nav.
   Hit Cmd+K (or "/") anywhere → fuzzy search pages, accounts, products.
   =========================================================================== */
.cmdk-overlay {
  position: fixed; inset: 0;
  z-index: 2000;
  display: flex; align-items: flex-start; justify-content: center;
  padding-top: 12vh;
  pointer-events: auto;
}
.cmdk-overlay[hidden] { display: none; }
.cmdk-backdrop {
  position: absolute; inset: 0;
  background: rgba(10, 14, 22, 0.6);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: pointer;
}
body.theme-light .cmdk-backdrop { background: rgba(60, 80, 110, 0.35); }
.cmdk-panel {
  position: relative;
  width: min(640px, calc(100vw - 32px));
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 14px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);
  overflow: hidden;
  animation: cmdk-rise 140ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes cmdk-rise { from { opacity: 0; transform: translateY(-8px) scale(0.98); } to { opacity: 1; transform: none; } }
.cmdk-input-wrap {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
.cmdk-input-icon { color: var(--muted); font-size: 16px; }
.cmdk-input {
  flex: 1;
  background: transparent;
  border: none;
  outline: none;
  color: var(--text);
  font-size: 14px;
  font-family: inherit;
  padding: 4px 0;
}
.cmdk-input::placeholder { color: var(--muted); }
.cmdk-kbd, .cmdk-kbd-tiny {
  display: inline-block;
  padding: 2px 6px;
  background: var(--surface-3);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 10px;
  font-family: ui-monospace, monospace;
  color: var(--muted);
  line-height: 1.2;
}
.cmdk-kbd-tiny { padding: 1px 4px; font-size: 9.5px; }
.cmdk-list {
  list-style: none;
  margin: 0; padding: 6px;
  max-height: 50vh;
  overflow-y: auto;
}
.cmdk-list::-webkit-scrollbar { width: 8px; }
.cmdk-list::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 4px; }
.cmdk-item {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 80ms ease;
}
.cmdk-item.active { background: var(--accent-soft); }
.cmdk-item:hover { background: var(--surface-2); }
.cmdk-item.active:hover { background: var(--accent-soft); }
.cmdk-item-icon {
  width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  font-size: 12px;
  color: var(--muted);
  flex-shrink: 0;
}
.cmdk-item.active .cmdk-item-icon { background: var(--accent); color: #fff; border-color: var(--accent); }
.cmdk-item-text { flex: 1; min-width: 0; }
.cmdk-item-label { font-size: 13px; font-weight: 500; color: var(--text); }
.cmdk-item-sub { font-size: 11px; color: var(--muted); margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmdk-item-type {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--muted);
  background: var(--surface-2);
  padding: 2px 6px;
  border-radius: 4px;
  flex-shrink: 0;
}
.cmdk-empty { padding: 24px; text-align: center; color: var(--muted); font-size: 12.5px; }
.cmdk-foot {
  display: flex; gap: 14px;
  padding: 8px 14px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  font-size: 10.5px;
  color: var(--muted);
}
@media (max-width: 600px) {
  .cmdk-overlay { padding-top: 6vh; }
  .cmdk-panel { width: calc(100vw - 16px); }
  .cmdk-foot { display: none; } /* keyboard hints are useless on mobile */
}

/* Cmd+K topbar trigger button (looks like a search input) */
.cmdk-trigger {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 10px 5px 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 12px;
  color: var(--muted);
  cursor: pointer;
  transition: border-color 80ms ease, background 80ms ease;
  min-width: 200px;
}
.cmdk-trigger:hover { border-color: var(--border-strong); background: var(--surface-3); }
.cmdk-trigger-icon { font-size: 13px; opacity: 0.7; }
.cmdk-trigger-text { flex: 1; text-align: left; }
.cmdk-trigger-kbd {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 6px;
  font-size: 10px;
  font-family: ui-monospace, monospace;
  color: var(--muted);
}
@media (max-width: 760px) { .cmdk-trigger-text, .cmdk-trigger-kbd { display: none; } .cmdk-trigger { min-width: 0; padding: 5px 8px; } }

/* ===========================================================================
   Welcome tour — first-login onboarding overlay.
   Linear / Notion / Stripe / Vercel pattern: centered modal card, dot progress,
   skip-link top-right, prev/next CTA, backdrop blur, keyboard navigation.
   =========================================================================== */
.wtour-overlay {
  position: fixed; inset: 0;
  z-index: 1900;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.wtour-overlay[hidden] { display: none; }
.wtour-backdrop {
  position: absolute; inset: 0;
  background: rgba(8, 12, 22, 0.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  cursor: pointer;
}
body.theme-light .wtour-backdrop { background: rgba(40, 60, 100, 0.45); }
.wtour-card {
  position: relative;
  width: min(500px, calc(100vw - 32px));
  background: linear-gradient(180deg, var(--surface) 0%, var(--surface-2) 100%);
  border: 1px solid var(--border-strong);
  border-radius: 16px;
  padding: 32px 32px 20px;
  box-shadow: 0 32px 80px rgba(0, 0, 0, 0.55), 0 4px 12px rgba(0, 0, 0, 0.25);
  animation: wtour-rise 200ms cubic-bezier(0.16, 1, 0.3, 1);
  outline: none;
}
@keyframes wtour-rise {
  from { opacity: 0; transform: translateY(8px) scale(0.97); }
  to { opacity: 1; transform: none; }
}
.wtour-skip {
  position: absolute; top: 14px; right: 16px;
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 12px;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 6px;
  transition: color 80ms ease, background 80ms ease;
}
.wtour-skip:hover { color: var(--text); background: var(--surface-3); }
/* Step content — re-animated on every transition */
.wtour-step {
  min-height: 220px;
  animation: wtour-step-in 240ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes wtour-step-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
.wtour-icon {
  display: inline-flex;
  width: 56px; height: 56px;
  align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--accent-soft), var(--surface-3));
  border: 1px solid var(--border-strong);
  border-radius: 14px;
  font-size: 28px;
  color: var(--accent);
  margin-bottom: 18px;
}
.wtour-title {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.3px;
  margin: 0 0 12px 0;
  color: var(--text);
}
.wtour-body {
  font-size: 14px;
  line-height: 1.6;
  color: var(--text);
}
.wtour-body p { margin: 0 0 12px 0; }
.wtour-body p:last-child { margin-bottom: 0; }
.wtour-body .hint { color: var(--muted); font-size: 13px; }
.wtour-body strong { font-weight: 600; }
.wtour-body kbd {
  display: inline-block;
  padding: 1px 7px;
  background: var(--surface-3);
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  font-family: ui-monospace, monospace;
  font-size: 11.5px;
  color: var(--text);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);
}
.wtour-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.wtour-dots { display: flex; gap: 8px; flex: 1; }
.wtour-dot {
  width: 8px; height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--border-strong);
  cursor: pointer;
  transition: background 120ms ease, transform 120ms ease;
}
.wtour-dot:hover { background: var(--muted); }
.wtour-dot.active {
  background: var(--accent);
  transform: scale(1.15);
}
.wtour-counter {
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.wtour-nav { display: flex; gap: 8px; }
.wtour-nav button {
  font-size: 13px;
  padding: 7px 14px;
  border-radius: 8px;
}
.wtour-prev {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
}
.wtour-prev:hover:not(:disabled) { color: var(--text); background: var(--surface-3); }
.wtour-prev:disabled { opacity: 0.4; cursor: default; }
.wtour-next {
  background: var(--btn-primary-bg);
  color: var(--btn-primary-fg);
  border: 1px solid var(--btn-primary-bg);
}
.wtour-next:hover {
  background: var(--btn-primary-bg-hover);
  border-color: var(--btn-primary-bg-hover);
  filter: brightness(1.05);
}
body.theme-light .wtour-next { color: var(--btn-primary-fg); }

/* Mobile: tighter spacing */
@media (max-width: 600px) {
  .wtour-card { padding: 24px 20px 16px; }
  .wtour-title { font-size: 18px; }
  .wtour-foot { flex-wrap: wrap; gap: 12px; }
  .wtour-counter { order: 3; flex-basis: 100%; text-align: center; margin-top: 4px; }
}

/* Topbar "?" tour-reopen button — sits next to Cmd+K trigger */
.tour-help-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--muted);
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  transition: border-color 80ms ease, color 80ms ease, background 80ms ease;
}
.tour-help-btn:hover { color: var(--accent); border-color: var(--border-strong); background: var(--surface-3); }

/* Notification mute toggle (bell). Same chip shape as tour-help-btn so the
   topbar's tiny-button row reads as one visual group. When muted, the bell
   gets a strike-through style to make the state obvious at a glance. */
.topbar-bell-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--muted);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  transition: border-color 80ms ease, color 80ms ease, background 80ms ease, opacity 80ms ease;
}
.topbar-bell-btn:hover { color: var(--accent); border-color: var(--border-strong); background: var(--surface-3); }
.topbar-bell-btn.muted { opacity: 0.55; }
.topbar-bell-btn.muted:hover { opacity: 1; }

/* ===========================================================================
   Accessibility: honor prefers-reduced-motion. Users with vestibular sensitivity
   (or who just disable motion in OS settings) shouldn't see the toast slide-in,
   modal scale, bulk-bar rise, skeleton shimmer, or any other animated effect.
   This nukes all transitions/animations down to ~0ms. CSS handles dozens of
   transition declarations — without this, motion is forced on every user.
   =========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ===========================================================================
   FSHIP — shipping integration section (admin-only).
   Scoped to .fship-* and the SHIPPING sidebar group.
   =========================================================================== */
.fship-strip {
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px;
  padding: 12px 16px; margin-bottom: 14px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
  font-size: 12.5px;
}
.fship-strip .hint strong { color: var(--text); }

.fship-steps {
  margin: 8px 0 16px 18px; padding: 0; line-height: 1.7; color: var(--muted); font-size: 13px;
}
.fship-steps li { margin-bottom: 4px; }
.fship-steps kbd {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px; padding: 1px 6px; border-radius: 4px;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
}

.fship-helper-script { margin: 6px 0 12px; }
.fship-helper-script summary {
  cursor: pointer; color: var(--muted); font-size: 12.5px;
  padding: 4px 0; user-select: none;
}
.fship-helper-script summary:hover { color: var(--text); }
.fship-helper-script pre {
  margin-top: 8px; padding: 12px 14px; border-radius: 6px;
  background: var(--surface-2); border: 1px solid var(--border);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; line-height: 1.5; overflow-x: auto; max-height: 280px;
  color: var(--text); white-space: pre;
}

#fship-token-blob {
  width: 100%; min-height: 110px; padding: 10px 12px; margin-top: 6px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; color: var(--text); resize: vertical;
}
#fship-token-blob:focus { outline: none; border-color: var(--accent); }

.fship-danger { border-color: rgba(244, 102, 102, 0.30); }
body.theme-light .fship-danger { border-color: rgba(196, 50, 50, 0.30); }

.btn-danger {
  background: var(--red-strong); color: white; border: 1px solid var(--red-strong);
  padding: 7px 14px; border-radius: 6px; font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.btn-danger:hover { filter: brightness(1.05); }

.fship-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.fship-form-row .control { display: flex; flex-direction: column; gap: 4px; }
.fship-form-row .control span { font-size: 12px; color: var(--muted); }
.fship-form-row .control input {
  padding: 9px 12px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 6px;
  color: var(--text); font-size: 13.5px; width: 100%; box-sizing: border-box;
}
.fship-form-row .control input:focus { outline: none; border-color: var(--accent); }
@media (max-width: 600px) { .fship-form-row { grid-template-columns: 1fr; } }

/* ===========================================================================
   SHIPPING — Overview / Shipments / NDR / Products page-level styles.
   All scoped under .ship-* so they don't bleed into Meta/Shopify pages.
   =========================================================================== */
.ship-action-panel { border-left: 3px solid var(--amber-strong); }
.ship-action-row {
  display: flex; align-items: center; gap: 12px; padding: 8px 0;
  border-bottom: 1px dotted var(--border);
}
.ship-action-row:last-child { border-bottom: none; }
.ship-action-row.sev-red .ship-action-icon { color: var(--red-strong); }
.ship-action-row.sev-amber .ship-action-icon { color: var(--amber-strong); }
.ship-action-icon { font-size: 16px; line-height: 1; }
.ship-action-text { flex: 1; }
.ship-action-text strong { color: var(--text); }

.ship-cashflow-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
}
.ship-cashflow-grid > div { padding: 8px 0; }
.ship-cashflow-grid .hint { font-size: 11.5px; }

/* Shipments page bulk-action workspace */
.ship-tabbar {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 10px 16px 0;
  border-bottom: 1px solid var(--border);
}
.ship-tab {
  padding: 8px 14px;
  background: transparent; border: 1px solid transparent; border-bottom: none;
  border-radius: 6px 6px 0 0;
  color: var(--muted); cursor: pointer; font-size: 12.5px; font-weight: 500;
  margin-bottom: -1px;
  white-space: nowrap;
}
.ship-tab:hover { color: var(--text); background: var(--surface-2); }
.ship-tab.active {
  color: var(--text); background: var(--surface);
  border-color: var(--border); border-bottom-color: var(--surface);
  font-weight: 600;
}
.ship-tab-count { color: var(--muted); font-weight: 400; font-size: 11px; margin-left: 4px; }
.ship-filter-row {
  display: flex; gap: 8px; padding: 12px 16px; flex-wrap: wrap; align-items: center;
}
.ship-filter-row input[type="search"], .ship-filter-row select {
  /* Use background-color (longhand) — the `background` shorthand would clobber
     the global select chevron's background-image + background-repeat:no-repeat
     and make the chevron data-URI tile across the whole select (looks like a
     scrambled-text overlay on the option labels). */
  padding: 6px 10px; background-color: var(--surface-2); border: 1px solid var(--border);
  border-radius: 6px; color: var(--text); font-size: 12.5px;
}
.ship-filter-row input[type="search"] { flex: 1; min-width: 240px; }
.ship-filter-row select { min-width: 120px; }
.ship-bulk-bar {
  display: flex; gap: 8px; padding: 10px 16px; align-items: center;
  background: var(--accent-faint); border-top: 1px solid var(--accent-mid);
  border-bottom: 1px solid var(--accent-mid);
}
.ship-bulk-bar #ship-sel-count, .ship-bulk-bar #ship-ndr-sel-count {
  font-weight: 600; color: var(--text); margin-right: 6px;
}
.ship-pager {
  display: flex; justify-content: space-between; align-items: center;
  padding: 10px 16px; gap: 12px;
}

/* NDR page two-column layout */
.ship-ndr-grid {
  display: grid; grid-template-columns: 260px 1fr; gap: 14px; align-items: start;
}
@media (max-width: 900px) { .ship-ndr-grid { grid-template-columns: 1fr; } }
.ship-ndr-aging-row, .ship-ndr-group-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 4px 0; border-bottom: 1px dotted var(--border);
}
.ship-ndr-aging-row:last-child, .ship-ndr-group-row:last-child { border-bottom: none; }

/* hidden attr must beat .ship-bulk-bar's display:flex */
.ship-bulk-bar[hidden] { display: none; }

/* ===========================================================================
   Fship slide-over panel — used for shipment detail + NDR-action forms.
   Right-edge drawer (like Linear / Notion), backdrop blur, ESC + click-out close.
   =========================================================================== */
.fship-slideover {
  position: fixed; inset: 0; z-index: 1000;
}
.fship-slideover-backdrop {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, 0.32);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  animation: fship-fade-in 120ms ease-out;
}
.fship-slideover-panel {
  position: absolute; right: 0; top: 0; bottom: 0;
  width: min(720px, 92vw);
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: -8px 0 30px rgba(0, 0, 0, 0.3);
  display: flex; flex-direction: column;
  animation: fship-slide-in 180ms cubic-bezier(0.4, 0, 0.2, 1);
}
body.theme-light .fship-slideover-panel { box-shadow: -8px 0 30px rgba(0, 0, 0, 0.12); }
.fship-slideover-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 22px; border-bottom: 1px solid var(--border);
}
.fship-slideover-head h3 { margin: 0; font-size: 16px; font-weight: 600; }
.fship-slide-close {
  background: transparent; border: 0; color: var(--muted);
  font-size: 24px; line-height: 1; cursor: pointer; padding: 0 6px;
  border-radius: 4px;
}
.fship-slide-close:hover { color: var(--text); background: var(--surface-2); }
.fship-slideover-body {
  padding: 18px 22px; overflow-y: auto; flex: 1;
}
.fship-slide-section { margin-bottom: 22px; }
.fship-slide-section h4 {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.6px;
  color: var(--muted); margin: 0 0 8px; font-weight: 600;
}
.fship-slide-status { display: flex; gap: 6px; margin-bottom: 6px; }
.fship-slide-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px 18px;
}
.fship-slide-grid > div { font-size: 13px; }
.fship-slide-grid .hint { font-size: 10.5px; margin-bottom: 2px; text-transform: uppercase; letter-spacing: 0.4px; }
@media (max-width: 600px) { .fship-slide-grid { grid-template-columns: 1fr 1fr; } }
.fship-slide-action-row {
  display: flex; gap: 8px; flex-wrap: wrap;
}

/* Tracking timeline — vertical dot+line layout */
.fship-timeline { list-style: none; padding: 0; margin: 0; position: relative; }
.fship-timeline::before {
  content: ''; position: absolute; left: 6px; top: 6px; bottom: 6px;
  width: 2px; background: var(--border);
}
.fship-timeline-item {
  display: flex; gap: 14px; padding: 6px 0 14px; position: relative;
}
.fship-timeline-dot {
  width: 14px; height: 14px; flex-shrink: 0;
  border-radius: 50%; background: var(--accent);
  border: 2px solid var(--surface);
  margin-top: 4px; z-index: 1;
}
.fship-timeline-item:first-child .fship-timeline-dot { background: var(--green-strong); }
.fship-timeline-item:last-child .fship-timeline-dot { background: var(--muted-2); }
.fship-timeline-body { flex: 1; line-height: 1.4; font-size: 12.5px; }
.fship-timeline-body .hint { font-size: 11px; margin-top: 2px; }

@keyframes fship-slide-in {
  from { transform: translateX(100%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}
@keyframes fship-fade-in {
  from { opacity: 0; } to { opacity: 1; }
}

.ship-row { cursor: pointer; }
.ship-row:hover { background: var(--surface-2); }
.ship-row-link { color: var(--accent); text-decoration: none; }
.ship-row-link:hover { text-decoration: underline; }

.ship-cashflow-spark { margin-top: 4px; opacity: 0.7; }
.ship-cashflow-spark svg { display: block; }

/* Suppress Chrome's autofill ghost-yellow + hatched pattern on filter selects.
   These selects are stateless filters, not credential inputs. */
.ship-filter-row select, .ship-filter-row input[type="search"] {
  -webkit-text-fill-color: var(--text) !important;
  background-color: var(--surface-2) !important;
}
.ship-filter-row select:-webkit-autofill,
.ship-filter-row input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 30px var(--surface-2) inset !important;
  -webkit-text-fill-color: var(--text) !important;
}

/* =============================================================== */
/* Group view panel for Shipments page (Booked tab > group by …)   */
/* =============================================================== */
.ship-group-panel {
  display: flex; gap: 8px; padding: 10px 16px; align-items: center;
  background: var(--accent-faint); border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.ship-group-btn { padding: 4px 12px; }
.ship-group-btn.active {
  background: var(--btn-primary-bg); color: var(--btn-primary-fg); border-color: var(--btn-primary-bg);
  font-weight: 600;
}

/* =============================================================== */
/* COD Forecast page                                                */
/* =============================================================== */
.cod-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.cod-tile {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 10px; padding: 16px 18px;
  border-left: 4px solid var(--accent);
}
.cod-tile-amber { border-left-color: var(--amber-strong, #d97706); }
.cod-tile-green { border-left-color: var(--green-strong, #16a34a); }
.cod-tile-red   { border-left-color: var(--red-strong, #dc2626); }
.cod-tile-blue  { border-left-color: var(--accent, #0066ff); }
.cod-tile-label {
  font-size: 12px; color: var(--muted); margin-bottom: 6px;
  text-transform: uppercase; letter-spacing: 0.04em;
}
.cod-tile-value {
  font-size: 22px; font-weight: 700; color: var(--text);
  line-height: 1.1;
}
.cod-tile-sub { font-size: 12px; color: var(--muted); margin-top: 4px; }

/* Horizontal bar for forecast weeks */
.cod-bar {
  height: 10px; background: var(--accent); border-radius: 4px;
  min-width: 2px; display: inline-block;
}

.cod-content { display: block; }

/* =============================================================== */
/* Couriers / Abandoned: percent badges                             */
/* =============================================================== */
.cr-pct {
  display: inline-block; padding: 2px 8px; border-radius: 4px;
  font-weight: 600; font-size: 12px; min-width: 50px; text-align: center;
}
.cr-pct-good { background: rgba(22, 163, 74, 0.12); color: var(--green-strong, #16a34a); }
.cr-pct-mid  { background: rgba(217, 119, 6, 0.12); color: var(--amber-strong, #d97706); }
.cr-pct-bad  { background: rgba(220, 38, 38, 0.12); color: var(--red-strong, #dc2626); }
.cr-table th { white-space: nowrap; }
.cr-table td.num { white-space: nowrap; }

/* =============================================================== */
/* Products page totals row                                         */
/* =============================================================== */
.ship-prod-totals strong { color: var(--text); }

/* =============================================================== */
/* NDR workspace — KPI tiles act as cohort selectors                */
/* =============================================================== */
.cod-tile[data-cohort-tile] { transition: transform 0.1s, box-shadow 0.1s; }
.cod-tile[data-cohort-tile]:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

/* NDR table — make recommendation badges and value cells comfortable */
#ndr-table .cr-pct { white-space: nowrap; }
#ndr-table td { vertical-align: top; }
#ndr-table .hint { font-size: 11.5px; line-height: 1.3; margin-top: 2px; }

/* Cohort tab bar — wider gap between tabs to read counts */
#ndr-cohort-tabs.ship-tabbar { padding: 10px 16px; gap: 8px; }

/* Order Journey state filter chips — active chip = filled accent */
#oj-state-chips button.btn-small.active {
  background: var(--btn-primary-bg); color: var(--btn-primary-fg); border-color: var(--btn-primary-bg);
  font-weight: 600;
}
#oj-state-chips button.btn-small { white-space: nowrap; }

/* Collapsible <details> cards (unshipped panel, etc.) */
details.card > summary { padding: 12px 16px; border-bottom: 0; }
details.card[open] > summary { border-bottom: 1px solid var(--border); }
details.card > summary::-webkit-details-marker { display: none; }
details.card > summary::before {
  content: '▸'; display: inline-block; margin-right: 8px;
  transition: transform 0.15s; color: var(--muted);
}
details.card[open] > summary::before { transform: rotate(90deg); }


