/* Shared design system — extracted from Design/Compliance Platform Design
   System.dc.html. One source of tokens + components for every screen so the
   app reads as one product, not sixteen independently-styled pages.

   ============================================================
   HOW THIS FILE IS ORGANIZED
   ============================================================
   Every section below is tagged with who consumes it, so you can tell at a
   glance whether a change is safe to make everywhere or will only affect
   one screen:

     [GLOBAL]  — design tokens, resets, or a component used across most/all
                 pages (buttons, inputs, cards, the legacy .chrome top bar,
                 status banners, pills, etc). Edit with care — it fans out.
     [SHARED]  — a component reused by a handful of specific pages (listed
                 in the section comment). Edit with those pages in mind.
     [PAGE]    — styles that only make sense on, and are only referenced
                 by, one specific page (or the admin console + its
                 partials, treated as one unit). Safe to change freely
                 without touching other screens.
     [RESERVED]— defined but not currently used by any page's markup; kept
                 for a future screen. Safe to repurpose or remove.

   Section order (top to bottom):
     1.  Design tokens (:root / dark theme)                        [GLOBAL]
     2.  Base reset + element defaults                              [GLOBAL]
     3.  Legacy top "chrome" bar (non-admin pages)                  [GLOBAL]
     4.  Layout wrappers (.center-wrap/.wrap-inner/.page-inner)     [GLOBAL]
     5.  Typography (.ds-h1/.text-secondary/.text-tertiary)        [GLOBAL]
     6.  Form fields                                                [GLOBAL]
     7.  Buttons                                                    [GLOBAL]
     8.  Path cards (landing intent picker)                       [RESERVED]
     9.  Segmented control                            [SHARED: report, reset-pin]
     10. Cards (.ds-card/.card-title/.card-grid)                    [GLOBAL]
     11. .section-title (reusable heading utility)         [GLOBAL utility —
         currently only consumed by admin-console.html; ORDER-SENSITIVE,
         see inline note]
     12. Hub cards                                        [PAGE: dashboard]
     13. AI insight card                     [SHARED: admin-console, report]
     14. Stat cards                [SHARED: admin-console, dashboard, landing, report]
     15. Two-column grid                     [SHARED: admin-console, report]
     16. Tenant/Lead list panels (#tenantList/#leadList)  [PAGE: admin-console]
     17. Star bars                                          [PAGE: report]
     18. Trend chart                                        [PAGE: report]
     19. Flagged reviews                                    [PAGE: report]
     20. Table (.ds-table)                              [PAGE: send-queue]
     21. List rows / avatar / badges / role chips     [mixed — see comments]
     22. Consent box                     [SHARED: intake, qr-intake]
     23. Empty states                    [SHARED: admin-console, onboarding —
         ORDER-SENSITIVE, see inline note]
     24. .section-sub (reusable body-copy utility)          [GLOBAL utility —
         currently only consumed by admin-console.html]
     25. Loading skeleton                                     [RESERVED]
     26. Status banner                                         [GLOBAL]
     27. Toast                              [GLOBAL — created dynamically by
         theme.js, not present in static markup]
     28. Admin console shell (sidebar/topbar + all responsive
         breakpoints)                [PAGE: admin-console + onboard-tenant
         + partials/admin-sidebar.html + partials/admin-topbar.html]
     29. Utility (.hidden/.spinner)                            [GLOBAL]

   IMPORTANT — do not reorder sections 10/11/23 relative to each other.
   .card-title, .section-title, and .empty-state-title all have equal CSS
   specificity (one class each) and are combined on the same elements in
   admin-console.html (e.g. class="card-title section-title" and
   class="empty-state-title section-title"). Since equal-specificity rules
   resolve by *source order* (last one wins), the current visual result
   depends on this file defining them in exactly this order:
     .card-title  →  .section-title  →  .empty-state-title
   Moving any of the three above/below this order will silently change
   font-size/color on admin-console.html's card headers or empty states. */

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');

/* ============================================================
   1. DESIGN TOKENS  [GLOBAL — every page reads these custom properties]
   ============================================================ */
:root {
  --bg-page: #F7F8FA;
  --bg-surface: #FFFFFF;
  --bg-inset: #F1F3F6;
  --border: #E4E7EC;
  --border-strong: #D0D5DD;
  --text-primary: #101828;
  --text-secondary: #475467;
  --text-tertiary: #0a0b0c;
  --shadow: 0 1px 2px rgba(16,24,40,0.05), 0 1px 3px rgba(16,24,40,0.08);
  --primary: #006389;
  --primary-dark: #004864;
  --primary-focus: rgba(0,99,137,0.18);
  /* .ds-card:hover and .ds-card.report-panel(-spaced):hover's glow (both
     site-wide) plus body.tenant-console .stat-card:hover's and
     body.tenant-console .tenant-console-onboarding-wrap .ds-card:hover's
     (tenant-console pages only — see admin-shell-loader.js) — deliberately
     its own token rather than reusing --primary-focus, which also drives
     every .ds-input:focus ring; 40% alpha reads well as a hover glow but
     would be too strong for a focus ring. Same rgb channels as --primary,
     just a stronger alpha. */
  --card-hover-glow: rgba(0,99,137,0.4);
  /* Hover-state glow for .btn-primary/.btn-primary-sm — kept as its own
     token (not computed inline in those rules) so public/brand.js can
     override it alongside --primary-dark when a tenant's own secondary
     brand color is set; otherwise a recolored button would still glow the
     default teal on hover. Same rgba values these rules used directly
     before this token existed — no visual change for tenants with no
     custom color. */
  --primary-glow: rgba(0,99,137,0.3);
  --primary-glow-sm: rgba(0,99,137,0.25);
  --success: #16A34A;
  --success-alt: #5C9A2E;
  --success-bg: #EEF7E4;
  --warn: #B54708;
  --warn-bg: rgba(247,144,9,0.14);
  --danger: #B42318;
  --danger-bg: #FEE4E2;
  --flag-bg: #FEF4F3;
  --flag-border: #FBDDD9;
  --ai-bg: #EFF8FC;
  --ai-border: #D3ECF6;
  --accent-purple: #7C3AED;
  --accent-purple-bg: rgba(124,58,237,0.12);
  --admin-nav-active-bg: #E5ECFA;
  --admin-nav-active-text: #000000;
  /* Stat-value accent colors (dashboard/report/admin-console/landing) — see
     dark-theme override below for why these need a separate dark variant
     instead of just reusing the raw hex everywhere. */
  --stat-blue: #0033A3;
  --stat-purple: #7C3AED;
  --stat-green: #0F9D58;
}

html[data-theme="dark"] {
  --bg-page: #0B0F14;
  --bg-surface: #11161C;
  --bg-inset: #161C24;
  --border: #232A33;
  --border-strong: #2E3742;
  --text-primary: #F2F4F7;
  --text-secondary: #98A2B3;
  --text-tertiary: #667085;
  --shadow: none;
  --success-bg: rgba(111,175,46,0.15);
  --danger-bg: rgba(240,68,56,0.15);
  --flag-bg: rgba(240,68,56,0.08);
  --flag-border: rgba(240,68,56,0.2);
  --ai-bg: rgba(0,99,137,0.10);
  --ai-border: rgba(0,99,137,0.25);
  --accent-purple-bg: rgba(124,58,237,0.18);
  /* Figma's sidebar mockup is light-mode only (#E5ECFA / #000 with no dark
     variant specified) — using those hardcoded on a dark sidebar would put
     black text on a light pill floating in a dark surface, and clash with
     the rest of the dark theme. Kept in the same family as the rest of the
     dark-mode primary/accent overrides instead. */
  --admin-nav-active-bg: rgba(0,66,209,0.18);
  --admin-nav-active-text: #F2F4F7;
  /* --stat-blue's light-mode value (#0033A3) was tuned for a white
     .stat-card — against the dark .stat-card surface above it drops well
     under WCAG AA contrast, so it needs its own brighter dark-mode value
     (unlike --stat-purple/--stat-green, which stay legible as-is). */
  --stat-blue: #6C93FF;
}

/* ============================================================
   2. BASE RESET + ELEMENT DEFAULTS  [GLOBAL — every page]
   ============================================================ */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: 'Inter', sans-serif;
  -webkit-font-smoothing: antialiased;
  background: var(--bg-page);
  color: var(--text-primary);
  transition: background 0.2s ease, color 0.2s ease;
}
input, select, button, textarea { font-family: 'Inter', sans-serif; }
a { color: var(--primary); text-decoration: none; }
a:hover { color: var(--primary-dark); }
p { font-weight: 400; font-size: 18px; line-height: 28px; letter-spacing: 0.03em; color: #000000; margin: 0; }
::selection { background: rgba(0,99,137,0.25); }
img { max-width: 100%;   }

@keyframes spin { to { transform: rotate(360deg); } }
@keyframes toastIn { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }
/* Plain opacity fade — no translate — for elements that aren't positioned
   via .toast's own `left: 50%` trick (toastIn's -50% transform assumes
   that positioning; applied elsewhere it reads as a slide-in from the
   left). Used by .toast-confirm-backdrop/.toast-confirm below. */
@keyframes confirmFadeIn { from { opacity: 0; } to { opacity: 1; } }

/* ============================================================
   3. LEGACY TOP "CHROME" BAR  [GLOBAL — used by every non-admin page:
      access-here, dashboard, feedback, index, intake, my-qr, onboarding,
      qr-intake, report, reset-pin, reset-staff-pin, send-queue.
      NOT used by admin-console.html/onboard-tenant.html — those use the
      newer .admin-shell/.admin-topbar system in section 28 instead.]
   ============================================================ */
.chrome {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 20px; border-bottom: 1px solid var(--border);
  background: var(--bg-surface); position: sticky; top: 0; z-index: 20;
  flex-wrap: wrap; gap: 10px;
}
.chrome-left { display: flex; align-items: center; gap: 10px; }
.logo-chip {
  background: #FFFFFF; border-radius: 8px; padding: 5px 10px;
  display: flex; align-items: center; border: 1px solid var(--border);
}
.logo-chip img { height: 22px; display: block; }
.chrome-divider { width: 1px; height: 20px; background: var(--border); }
.chrome-label { font-size: 13px; font-weight: 600; color: var(--text-secondary); }
.toggle-btn {
  background: var(--bg-inset); border: 1px solid var(--border); color: var(--text-primary);
  border-radius: 8px; padding: 7px 12px; font-size: 13px; font-weight: 600; cursor: pointer; letter-spacing: 0.03em;
}

/* ============================================================
   4. LAYOUT WRAPPERS  [GLOBAL — center-wrap/wrap-inner used by 8 pages;
      page-inner used by 7 pages, incl. admin-console/onboard-tenant]
   ============================================================ */
.center-wrap {
  min-height: calc(100vh - 53px); display: flex; align-items: center;
  justify-content: center; padding: 24px;
}
.center-wrap.top-align { align-items: flex-start; padding: 0; }
.wrap-inner { width: 100%; max-width: 420px; }
.wrap-inner.wide { max-width: 440px; }
/* [PAGE: onboard-tenant.html] — scoped via the .admin-content ancestor
   (unique to admin-console.html/onboard-tenant.html) so intake.html's own
   .wrap-inner.wide keeps its 440px cap. */
.admin-content .wrap-inner.wide { max-width: none; width: 100%; }
.page-inner { max-width: 1080px; margin: 0 auto; padding: 32px 24px 64px; }

/* ============================================================
   5. TYPOGRAPHY  [GLOBAL — text-secondary/text-tertiary used on nearly
      every page; ds-h1 on the auth-style single-column pages]
   ============================================================ */
h1.ds-h1 { font-size: 26px; font-weight: 800; margin: 0; letter-spacing: -0.02em; color: var(--text-primary); }
.text-secondary { font-size: 14px; color: var(--text-secondary); }
.text-tertiary { font-size: 12px; color: var(--text-tertiary); }

/* ============================================================
   6. FORM FIELDS  [GLOBAL — used on every page with a form]
   ============================================================ */
label.field-label { display: block; font-size: 13px; font-weight: 600; color: var(--text-secondary); margin-bottom: 6px; }
.ds-input, select.ds-input {
  width: 100%; padding: 11px 13px; border-radius: 9px; border: 1px solid var(--border);
  background: var(--bg-surface); color: var(--text-primary); font-size: 14px; outline: none;
}
.ds-input.lg { padding: 14px; border-radius: 10px; font-size: 16px; }
.ds-input:focus, select.ds-input:focus {
  border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-focus);
}
.ds-input.invalid { border-color: var(--danger); }
.ds-input.invalid:focus { box-shadow: 0 0 0 3px var(--danger-bg); }
.field-error { display: block; color: var(--danger); font-size: 12px; font-weight: 600; margin-top: 5px; }

/* ============================================================
   7. BUTTONS  [GLOBAL — btn-primary used on 11 pages incl. admin-console/
      onboard-tenant; the rest used across most other pages too]
   ============================================================ */
.btn-primary {
  width: 100%; padding: 13px; border-radius: 29.5px; border: none; background: var(--primary);
  color: #fff; font-size: 15px; font-weight: 700; cursor: pointer; transition: all 0.15s ease; text-transform: uppercase;
  letter-spacing: 0.03em;
}
/* color: #fff restated here (not just inherited from the base rule above) —
   theme.css's global `a:hover { color: var(--primary-dark) }` (section 3)
   has higher specificity than a bare `.btn-primary` class selector, so on
   any <a class="btn-primary"> (e.g. admin-console.html's "Convert to
   tenant", the landing page hero CTA) it would otherwise win and set the
   text color to the exact same value as this rule's own hover background,
   making the label invisible. */
.btn-primary:hover { background: var(--primary-dark); box-shadow: 0 4px 12px var(--primary-glow); color: #fff; }
.btn-primary:active { transform: scale(0.98); }
.btn-primary:disabled { opacity: 0.6; cursor: default; }
.btn-primary.lg { padding: 15px; font-size: 16px; }
.btn-primary.auto { width: auto; padding: 12px 24px; }

.btn-secondary-sm {
  padding: 8px 14px; border-radius: 29.5px; border: 1px solid var(--border-strong);
  background: var(--bg-surface); color: var(--text-primary); font-size: 13px; font-weight: 600; cursor: pointer;
  letter-spacing: 0.03em; transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
/* Same flat hover treatment as .admin-icon-btn:hover — background shifts
   to --bg-inset; color is already --text-primary at rest, restated here so
   it doesn't get treated as an oversight later. */
.btn-secondary-sm:hover { background: var(--bg-inset); color: var(--text-primary); }
.btn-secondary-sm:disabled { opacity: 0.6; cursor: default; }
/* .btn-danger-sm — [GLOBAL] same shape/sizing as .btn-secondary-sm, for a
   small destructive inline action (e.g. "Remove") — soft danger tint at
   rest (same --danger/--danger-bg pairing as .rating-chip/.pill-declined
   elsewhere), inverts to solid red on hover as a clearer "this removes
   something" cue than the neutral secondary style gave it. */
.btn-danger-sm {
  padding: 8px 14px; border-radius: 29.5px; border: 1px solid var(--danger-bg);
  background: var(--danger-bg); color: var(--danger); font-size: 13px; font-weight: 600; cursor: pointer;
  transition: all 0.15s ease; text-transform: uppercase; letter-spacing: 0.03em;
}
.btn-danger-sm:hover { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-danger-sm:disabled { opacity: 0.6; cursor: default; }
/* .btn-primary-sm — [GLOBAL] a small filled-primary pill, for a per-row or
   inline action (e.g. table "Send now") that's the main thing to do there
   but doesn't warrant a full-width .btn-primary. */
.btn-primary-sm {
  width: auto; padding: 8px 16px; border-radius: 999px; border: none; background: var(--primary);
  color: #fff; font-size: 13px; font-weight: 700; cursor: pointer; transition: all 0.15s ease; white-space: nowrap; text-transform: uppercase;
  letter-spacing: 0.03em;
}
/* color: #fff restated for the same reason as .btn-primary:hover above —
   <a class="btn-primary-sm"> (e.g. staff-notifications.html's "Reset the
   code") would otherwise get its hover text color hijacked by the global
   a:hover rule, matching the hover background exactly and erasing the
   label. */
.btn-primary-sm:hover { background: var(--primary-dark); box-shadow: 0 4px 10px var(--primary-glow-sm); color: #fff; }
.btn-primary-sm:disabled { opacity: 0.6; cursor: default; }
/* Buttons keep their normal hover everywhere, including the Repzy admin
   console — only card-surface hover glow (.ds-card, .stat-card) is the
   brand-color effect scoped away from admin-console.html/
   admin-notifications.html/admin-profile.html/onboard-tenant.html below.
   admin-console.html never loads public/brand.js anyway, so this hover
   always uses the fixed default --primary-dark/--primary-glow, never a
   tenant's own color. */
.btn-ghost {
  padding: 8px 12px; border-radius: 29.5px; border: none; background: transparent;
  color: var(--text-secondary); font-size: 13px; font-weight: 600; cursor: pointer; letter-spacing: 0.03em;
}
.btn-back {
  background: none; border: none; padding: 0; color: var(--text-secondary);
  font-size: 13px; font-weight: 600; cursor: pointer; align-self: flex-start; text-align: left; letter-spacing: 0.03em;
}
.link-forgot { text-align: center; font-size: 13px; font-weight: 600; display: block; margin-top: 2px; }
.btn-icon {
  width: 30px; height: 30px; border-radius: 29.5px; border: 1px solid var(--border);
  background: var(--bg-surface); color: var(--text-secondary); cursor: pointer; font-size: 13px; letter-spacing: 0.03em;
}

/* ============================================================
   8. PATH CARDS (landing intent picker)  [RESERVED — .path-card/.path-icon/
      .path-title/.path-sub aren't referenced by any page's markup right
      now despite the "landing" name; kept for a future intent-picker
      screen. .chevron below is a separate, currently-used generic icon
      color utility — see next line.]
   ============================================================ */
.path-card {
  display: flex; align-items: center; gap: 14px; width: 100%; padding: 18px;
  border-radius: 12px; border: 1px solid var(--border); background: var(--bg-surface);
  cursor: pointer; box-shadow: var(--shadow); transition: all 0.15s ease; text-align: left;
}
.path-card:hover { transform: translateY(-1px); box-shadow: 0 4px 14px rgba(16,24,40,0.10); }
.path-card:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.path-icon {
  width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center;
  justify-content: center; font-size: 18px; font-weight: 700; flex-shrink: 0;
}
.path-title { display: block; font-weight: 700; font-size: 16px; }
.path-sub { display: block; font-size: 13px; color: var(--text-secondary); }
/* .chevron — [GLOBAL utility, currently used by reset-staff-pin.html] */
.chevron { color: var(--text-tertiary); font-size: 18px; }

/* ============================================================
   9. SEGMENTED CONTROL  [SHARED: report.html, reset-pin.html]
   ============================================================ */
.segmented {
  display: inline-flex; background: var(--bg-inset); border-radius: 9px; padding: 0;
  flex-wrap: wrap; gap: 8px;
}
.seg-btn {
  padding: 8px 32px; border-radius: 5px; border: 1px solid var(--border-strong); background: var(--bg-surface);
  color: var(--text-primary); font-weight: 400; font-size: 16px; line-height: 27px; letter-spacing: 0.03em; cursor: pointer;
}
.seg-btn.sm { padding: 6px 12px; font-size: 12.5px; }
.seg-btn.active { background: var(--primary); color: #fff; border-color: var(--primary); }

/* ============================================================
   10. CARDS  [GLOBAL — ds-card/card-title used on 12 and 5 pages
       respectively (incl. admin-console/onboard-tenant); card-grid is
       currently dashboard.html only but kept here as it's the same
       component family]
   ============================================================
   NOTE: .card-title must stay defined BEFORE .section-title below — see
   the file-level "IMPORTANT" note at the top of this file for why. */
.ds-card { background: var(--bg-surface);
    box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.15);
    border-radius: 10px;
    padding: 50px 160px;
    border: none;
    transition: box-shadow 0.2s ease; }
/* Light colored glow on hover, layered on top of the existing ambient
   shadow rather than replacing it — --primary-focus is already primary at
   18% alpha (see theme.css :root + public/brand.js), so this automatically
   follows a tenant's own brand color once set, same as every other
   --primary-focus consumer (.ds-input:focus etc.). */
.ds-card:hover { box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.15), 0 0 24px var(--card-hover-glow); }
/* Same admin-console-vs-tenant-console gate as the .btn-primary override
   above — .ds-card is used on admin-console.html/admin-notifications.html/
   admin-profile.html/onboard-tenant.html too, so without this it keeps the
   brand-color glow on hover there even though those pages never load
   public/brand.js. Flat ambient shadow only, no glow. */
body:not(.tenant-console) .admin-shell .ds-card:hover {
  box-shadow: 0px 30px 68px rgba(0, 0, 0, 0.22);
}
.card-title { font-size: 14px; font-weight: 700; color: var(--text-primary); }
.card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 16px; }
/* [PAGE: dashboard.html] 335px hub-card columns, wrapping naturally (4-up
   at typical desktop widths) instead of the generic minmax(230px,1fr)
   above — see section 12 below for why dashboard.html needs its own grid.
   minmax(min(335px, 100%), 1fr) — not a fixed 335px track — is what makes
   this hold from 1300px down to 320px: a fixed-length track can't shrink
   below its own size, so once the viewport (minus sidebar/content padding)
   dropped under ~375px the old fixed-335px track forced a horizontal
   scrollbar on the whole page. min(335px, 100%) caps the track at the
   container's own width instead, so it shrinks to fit on narrow phones
   while still behaving like a plain 335px track (and still packing 2–4 up)
   on anything wide enough to hold one. */
/* auto-fill, not auto-fit — with auto-fit, hiding cards (e.g. a "staff"
   role that only sees 2 of the 6 hub cards) collapses the unused track(s)
   and lets the 1fr tracks stretch to fill the row, which pushes the
   remaining cards apart with dead space between them (each card still caps
   at max-width:337px, so it just sits stranded at the left of its now-wider
   track). auto-fill keeps the same number of tracks either way, so the
   leftover space collects in trailing empty track(s) after the last visible
   card instead of gaps between visible ones — cards stay packed tight on
   the left regardless of how many are hidden. */
.card-grid.hub-card-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 40px; }
/* Below 3 tracks' worth of comfortable card width, drop to 2 then 1 column
   so cards don't get squeezed thinner than their content (icon + heading +
   description) can read — same "no horizontal scroll on narrow phones"
   goal as the old auto-fill/minmax(335px) approach, just via explicit
   breakpoints now that the column count itself is fixed at 3. minmax(0,1fr)
   (not plain 1fr) at every step keeps a track from refusing to shrink below
   its content's intrinsic width, which is what caused the old fixed-335px
   track to force a scrollbar in the first place. */
@media (max-width: 900px) {
  .card-grid.hub-card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .card-grid.hub-card-grid { grid-template-columns: minmax(0, 1fr); }
}
/* [PAGE: report.html] compact panel variant — the 50px/160px default above
   is sized for centered single-column auth-style cards, not report.html's
   dense multi-panel layout. */
.ds-card.report-panel {
  background: var(--bg-surface); border: 1px solid var(--border); box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.04);
  border-radius: 10px; padding: 45px 28px;
}
.ds-card.report-panel-spaced {
  background: var(--bg-surface); border: 1px solid var(--border); box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.04);
  border-radius: 10px; padding: 38px 28px; margin-top: 20px;
}
/* .report-panel/-spaced redeclare box-shadow above at equal specificity to
   (and after) .ds-card:hover, which would otherwise silently cancel its
   glow on hover — restated here against their own lighter 0.04 ambient
   shadow instead of .ds-card's 0.15, same --card-hover-glow token
   (brand primary at 40% alpha — see the :root definition + public/brand.js). */
.ds-card.report-panel:hover, .ds-card.report-panel-spaced:hover {
  box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.04), 0 0 24px var(--card-hover-glow);
}
/* Figma names this cut "Inter 18pt" (an optical-size instance name), but
   only the base 'Inter' family is loaded (see the @import above) — mapped
   to that so the heading doesn't fall back to the system default font. */
.report-panel .section-title, .report-panel-spaced .section-title { font-family: 'Inter', sans-serif; font-size: 18px; }
.report-panel .section-subtitle { font-size: 16px; line-height: 34px; color: var(--text-primary); }

/* ============================================================
   11. .section-title  [GLOBAL utility — written to be reusable by any
       dashboard card/panel heading; consumed by admin-console.html and
       report.html. ORDER-SENSITIVE: must stay after .card-title
       (above) and before .empty-state-title (section 23) — see the
       file-level "IMPORTANT" note at the top of this file.]
   ============================================================
   Reused anywhere a dashboard card/panel needs the same heading treatment
   (AI insight label, card titles, empty-state titles, stat labels). One
   rule to tweak instead of repeating the same six properties on every
   heading class. */
.section-title {
  font-weight: 700; font-size: 16px; line-height: 34px; letter-spacing: 0.03em;
  text-transform: uppercase; color: var(--text-primary);
}

/* [PAGE: report.html] — the smaller second-tier label under a
   .section-title, e.g. "Rating distribution" underneath "Performance
   overview". Not needed anywhere .section-title is already used alone. */
.section-subtitle {
  display: block; font-weight: 700; font-size: 12px; letter-spacing: 0.03em;
  text-transform: uppercase; color: var(--text-tertiary); margin-top: 2px;
}

/* ============================================================
   12. HUB CARDS  [PAGE: dashboard.html]
   ============================================================
   Each card sets --hub-accent inline (its "outer color") — drives the top
   border, icon-circle tint (via color-mix), and the View-more CTA/arrow, so
   changing a card's category color is a one-line edit instead of touching
   three properties. Icon images (assets/dash_icon1.svg etc.) are separate
   files with the matching color already baked in, since an <img>-loaded SVG
   can't pick up currentColor from the page. */
/* width/min-height (not the old fixed width: 337px; height: 350px) so the
   card fills whatever width its now-fluid .hub-card-grid track gives it
   (see section 10) instead of overflowing it below ~375px, and so a card
   whose .hub-sub wraps to an extra line on a narrow phone grows instead of
   clipping/overlapping .hub-cta. */
.hub-card {
  text-align: left; box-sizing: border-box; width: 100%; min-height: 350px;
  padding: 27px; border-radius: 20px; border-top: 8px solid var(--hub-accent, #0368EB);
  background: var(--bg-surface); cursor: pointer; box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.15);
  transition: all 0.15s ease; display: flex; flex-direction: column;
}
.hub-card:hover { box-shadow: 0px 30px 68px rgba(0, 0, 0, 0.2); }
/* The circle background is baked into each dash_iconN.svg itself (not
   CSS) — an <img>-loaded SVG can't inherit currentColor/color-mix from the
   page, so each icon file already contains its own tinted circle + glyph. */
.hub-icon { width: 56px; height: 56px; display: block; margin-bottom: 18px; flex-shrink: 0; }
/* Same look as .admin-form .card-title (uppercase/700/20px/0.03em), just
   with its own margin-bottom per the hub-card spec instead of that rule's
   15px. */
.hub-title {
  display: block; font-weight: 700; font-size: 20px; line-height: 34px; letter-spacing: 0.03em;
  text-transform: uppercase; color: var(--text-primary); margin: 0 0 6px;
}
.hub-sub { font-size: 15px; line-height: 1.5; color: var(--text-secondary); margin: 0 0 23px; }
.hub-cta {
  display: inline-flex; align-items: center; gap: 8px; margin-top: auto;
  font-weight: 700; font-size: 15px; color: var(--hub-accent, #0368EB);
}
.hub-cta svg { flex-shrink: 0; }
/* dashboard.html's "Business Settings" card is the one hub card whose
   accent isn't set inline via style="--hub-accent:...", unlike the other
   five (#0042D1/#0F9D58/#7C3AED/#06B6D4/#EA580C) — on purpose, so a
   dark-mode override here in the stylesheet actually has a chance to win.
   An inline style="" always beats an external rule for the same property
   regardless of selector specificity (short of !important), so as long as
   this card set --hub-accent inline the html[data-theme="dark"] override
   below could never apply no matter how it was written — the border/CTA/
   icon stayed the light-mode #1E293B (near-black slate, fine on a white
   card) even in dark mode, nearly invisible against the dark .hub-card
   surface. Base value here matches the old inline one for light mode;
   #94A3B8 is the dark-mode-only replacement, chosen for ~6.5:1 contrast
   against the card's #11161C background (a #64748B first attempt only
   cleared ~4:1 — legible but dim in practice). */
#settingsCard { --hub-accent: #1E293B; }
html[data-theme="dark"] #settingsCard { --hub-accent: #94A3B8; }

/* ============================================================
   13. AI INSIGHT CARD  [SHARED: admin-console.html + report.html]
       .ai-card / .ai-badge / .ai-text — the base card, used by both pages.
       .ai-card-row / .ai-card-content / .ai-card-graphic — admin-console's
       layout variant (with the decorative graphic) only.
       .ai-label — report.html's own heading style only (admin-console
       uses .section-title instead, per section 11).
   ============================================================ */
.ai-card { background: var(--ai-bg); border: 1px solid var(--ai-border); border-radius: 10px; padding: 14px 32px; min-height: 166px; margin-bottom: 36px; display: flex; align-items: center; transition: box-shadow 0.2s ease; }
.ai-card:hover { box-shadow: 0px 20px 48px rgba(0, 0, 0, 0.10); }
.ai-card-row { display: flex; align-items: center; justify-content: space-between; gap: 80px; width: 100%; }
.ai-card-content { display: flex; align-items: center; gap: 30px; }
.ai-card-graphic { flex-shrink: 0; width: 309px; height: 127px; opacity: 0.55; }
.ai-badge {
  flex-shrink: 0; width: 66px; height: 66px; border-radius: 50%; background: #0042D1;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 24px; line-height: 34px; letter-spacing: 0.03em; text-transform: uppercase; color: #FFFFFF;
}
.ai-label { font-size: 16px; font-weight: 700; line-height: 34px; letter-spacing: 0.03em; text-transform: uppercase; color: var(--text-primary); }
/* Explicit color (not just inherited from body) because .ai-text is a <p>,
   and the global `p { color: #000000; }` reset (section 2) beats inherited
   color on specificity — without this, the text renders as invisible
   near-black on .ai-card's dark-mode background instead of following the
   theme. */
.ai-text { margin: 6px 0 0; color: var(--text-secondary); }

/* ============================================================
   14. STAT CARDS  [SHARED: admin-console, dashboard, landing, report]
       .stat-grid / .stat-card / .stat-value — used by all four pages.
       .stat-text / .stat-icon-chip — admin-console.html's icon-chip
       variant only. .stat-delta / .stat-value-row / .stat-sparkline —
       report.html's trend-line variant only. .stat-label — used by
       dashboard/landing/report (NOT admin-console, which uses
       .section-title instead, per section 11).
   ============================================================ */
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 18px; margin-bottom: 40px; }
.stat-card {
  background: var(--bg-surface); border: 1px solid var(--border); border-radius: 10px; padding: 30px 26px;
  display: flex; flex-direction: row; align-items: center; gap: 16px; box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.06); justify-content: flex-start; min-height: 150px;
  transition: box-shadow 0.2s ease;
}
/* Same --card-hover-glow treatment as .ds-card:hover (brand primary at 40%
   alpha — see the :root definition + public/brand.js): layered on top of the
   existing ambient shadow rather than replacing it, so this follows a
   tenant's own brand color once set. Scoped to body.tenant-console (set by
   admin-shell-loader.js) — .stat-card is also used by admin-console.html
   and landing.html, which stay on the flat default shadow with no glow. */
body.tenant-console .stat-card:hover { box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.06), 0 0 24px var(--card-hover-glow); }
/* Plain shadow-only hover for admin-console.html (no brand glow there,
   same admin-console-vs-tenant-console split as .ds-card:hover above) —
   without this, .stat-card had a box-shadow transition wired up but no
   :hover rule at all outside tenant-console, so hovering did nothing. */
body:not(.tenant-console) .stat-card:hover { box-shadow: 0px 30px 68px rgba(0, 0, 0, 0.12); }

.stat-text { display: flex; flex-direction: column; }
.stat-label { font-size: 16px; font-weight: 700; line-height: 34px; letter-spacing: 0.03em; text-transform: uppercase; color: var(--text-primary); }
.stat-value-row { display: flex; align-items: baseline; gap: 8px; }
.stat-value { font-size: 40px; font-weight: 700; line-height: 34px; letter-spacing: 0.03em; text-transform: uppercase; color: var(--stat-blue); font-variant-numeric: proportional-nums; }
.stat-delta { font-size: 12px; font-weight: 700; display: inline-flex; align-items: center; gap: 2px; }
.stat-delta.up { color: var(--success); }
.stat-delta.down { color: var(--danger); }
.stat-delta.flat { color: var(--text-tertiary); }
.stat-sub { font-size: 11.5px; color: var(--text-tertiary); }
.stat-sparkline { width: 100%; height: 28px; margin-top: 2px; display: block; }
/* [PAGE: report.html] stat-value color variants (sent/clicked/CTR) */
.stat-value.stat-value-sent { color: var(--stat-blue); }
.stat-value.stat-value-clicked { color: var(--stat-purple); }
.stat-value.stat-value-ctr { color: var(--stat-green); }

/* ============================================================
   15. TWO-COLUMN GRID  [SHARED: admin-console.html, report.html]
   ============================================================ */
.two-col { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; margin-bottom: 20px; }

/* ============================================================
   16. TENANT / LEAD LIST PANELS  [PAGE: admin-console.html]
   ============================================================ */
/* Overrides .ds-card's default padding: 50px 160px — sized for a narrow
   auth-style card (login etc.), not a wide dashboard panel; left at the
   default it crowds #tenantList/#leadList's own content against the card
   edges unevenly (huge left/right gutters, comparatively little top/bottom). */
#tenantPerformanceCard, #leadPipelineCard { padding: 33px; }
/* Tenant/lead detail modal (admin-console.html's shared #detailModalCard
   shell, filled via openDetailModal()) — its several sections (Record a
   renewal payment, Custom login domain, Google review link, Staff,
   Branches) previously reused the bare .card-title look (14px, no color),
   same as a card's own title bar, which reads flat and doesn't separate
   from the body text below it. Scoped to the modal (not a bare .card-title
   override) so this doesn't touch every other card's title elsewhere. */
#detailModalCard .card-title,
#reassignSection .card-title, #resetSection .card-title, #deactivateSection .card-title {
  display: block; font-size: 16px; letter-spacing: 0.06em; text-transform: uppercase;
  color: #0042D1; margin-bottom: 6px;
}
/* staff-detail.html's own subsection headers (Branch/zone assignment,
   Reset login, Deactivate) previously used the bare .card-title look —
   flat, small, no color — same problem #detailModalCard's sections had
   before the rule above, and the same fix: scoped to these three section
   ids rather than a bare .card-title override, so every other card's own
   title bar elsewhere in the app is untouched. */
/* Same reasoning as .admin-form .btn-primary's bump to 18px/12px-25px —
   the modal's own "Record payment"/"Convert to tenant" CTAs used the plain
   .btn-primary (15px, 13px padding), which reads small against the rest of
   the (now-larger) primary buttons across the app. Also on the fixed Repzy
   blue rather than var(--primary) — same reasoning as #topbarPrimaryAction
   above: this modal only ever opens from admin-console.html (Repzy-staff
   only), never a tenant-console page, so there's no brand color to defer
   to here either. */
#detailModalCard .btn-primary {
  font-size: 18px; min-height: 56px; padding: 12px 25px;
  background: #0042D1;
}
#detailModalCard .btn-primary:hover { background: #0036AB; }
#tenantList, #leadList {
  margin-top: 26px; background: #F2F3F7; border-radius: 10px; min-height: 370px;
  display: flex; flex-direction: column; justify-content: center;
}
#tenantList .empty-state, #leadList .empty-state { background: transparent; border: none; }

/* ============================================================
   17. STAR BARS  [PAGE: report.html]
   ============================================================ */
.bar-row { display: flex; align-items: center; gap: 10px; }
.bar-label { width: 38px; font-size: 13px; font-weight: 600; color: var(--text-secondary); }
.bar-track { flex: 1; height: 10px; border-radius: 999px; background: var(--bg-inset); overflow: hidden; }
.bar-fill { height: 100%; width: var(--w, 0%); border-radius: 999px 999px 999px 999px; transition: width 0.4s ease; }
.bar-count { width: 24px; text-align: right; font-size: 13px; font-weight: 600; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.bar-row { position: relative; }
.bar-row[data-tip]:hover .bar-track, .bar-row[data-tip]:focus-within .bar-track { outline: none; }
/* Rating-tier color variants — width stays a --w custom property (the one
   thing that has to stay per-element, since it's a continuous value
   computed from live data; see report.html's renderReport()). */
.bar-fill.bar-fill-success { background: var(--success); }
.bar-fill.bar-fill-warn { background: var(--warn); }
.bar-fill.bar-fill-danger { background: var(--danger); }

/* ============================================================
   18. TREND CHART (7-day CTR)  [PAGE: report.html]
   ============================================================ */
.trend-wrap { position: relative; margin-top: 10px; }
.trend-svg { width: 100%; height: 110px; display: block; }
.trend-crosshair { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--border-strong); pointer-events: none; opacity: 0; transition: opacity 0.1s ease; }
.trend-tooltip {
  position: absolute; pointer-events: none; opacity: 0; transition: opacity 0.1s ease;
  background: var(--bg-surface); border: 1px solid var(--border-strong); border-radius: 8px;
  padding: 8px 10px; font-size: 12px; box-shadow: var(--shadow); white-space: nowrap; z-index: 5;
}
.trend-tooltip-value { font-weight: 700; color: var(--text-primary); font-size: 13px; }
.trend-tooltip-label { color: var(--text-tertiary); margin-top: 1px; }
.trend-labels { display: flex; justify-content: space-between; font-size: 10.5px; color: var(--text-tertiary); margin-top: 2px; }

/* ============================================================
   19. FLAGGED REVIEWS  [PAGE: report.html]
   ============================================================ */
.flag-row { padding: 22px 20px; border-radius: 10px; background: var(--flag-bg); border: 1px solid var(--flag-border); }
.rating-chip { font-size: 12px; font-weight: 700; color: var(--danger); background: var(--danger-bg); border-radius: 999px; padding: 2px 9px; flex-shrink: 0; }
.flag-row-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.flag-customer-name { font-weight: 700; font-size: 16px; line-height: 34px; letter-spacing: 0.03em; text-transform: uppercase; color: var(--text-primary); }
.flag-review-text { margin: 6px 0 0; font-weight: 400; font-size: 15px; line-height: 28px; letter-spacing: 0.03em; color: var(--text-primary); }
.flag-staff-meta { display: block; margin-top: 0; font-weight: 400; font-size: 13px; line-height: 28px; letter-spacing: 0.03em; color: var(--text-primary); }

/* ============================================================
   20. TABLE  [GLOBAL — reusable data-table component, any page can adopt
       this instead of hand-rolling table markup/inline styles]
   ============================================================
   Usage:
     <div class="ds-table-scroll">
       <table class="ds-table">...</table>
     </div>
   Cell-content helpers (compose these instead of inline styles):
     .table-person        — flex row for an avatar + name/meta cell
                             (pair with the global .avatar; add
                             .avatar-accent for a filled-primary variant)
     .table-title          — bold primary-color line (e.g. a name)
     .table-sub             — smaller muted line under a .table-title
     .table-actions         — flex row for inline per-row controls
     .table-select-sm       — compact <select> sized for a table cell
     .table-empty            — the "nothing here" message under a table
   See send-queue.html for a full example. */
.ds-table-scroll { overflow-x: auto; }
.ds-table { width: 100%; border-collapse: collapse; min-width: 520px; }
.ds-table th {
  text-align: left; font-size: 12px; font-weight: 700; color: var(--text-secondary);
  text-transform: uppercase; letter-spacing: 0.03em; padding: 0 10px 10px; border-bottom: 1px solid var(--border);
}
.ds-table td { font-size: 14px; padding: 12px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.ds-table tbody tr:last-child td { border-bottom: none; }
.ds-table tbody tr:hover { background: rgba(127,127,127,0.06); }

.table-person { display: flex; align-items: center; gap: 10px; }
.avatar.avatar-accent { background: var(--primary); color: #fff; }
/* [PAGE: report.html] leaderboard/callout avatar fill variants — compound
   with the base .avatar above rather than redefining it, so
   onboarding.html/reset-staff-pin.html/admin-topbar's plain .avatar (no
   colored fill) is unaffected. */
.avatar.avatar-good { background: var(--success); color: #fff; font-weight: 700; font-size: 12.5px; }
.avatar.avatar-warn { background: var(--warn); color: #fff; font-weight: 700; font-size: 12.5px; }
.avatar.avatar-neutral { background: var(--primary); color: #fff; font-weight: 700; font-size: 12.5px; }
.table-title { display: block; font-weight: 600; color: var(--text-primary); }
.table-sub { display: block; font-size: 12px; color: var(--text-tertiary); margin-top: 1px; }
.table-actions { display: flex; align-items: center; gap: 14px; }
.table-select-sm { width: auto; padding: 4px 8px; font-size: 12px; }
.table-empty { margin-top: 14px; color: var(--text-tertiary); }

/* ============================================================
   21. LIST ROWS / AVATAR / BADGES / ROLE CHIPS  [mixed scope — see each
       class below]
   ============================================================ */
/* .list-row — [SHARED: admin-console.html, onboarding.html] */
.list-row {
  display: flex; align-items: center; justify-content: space-between; padding: 13px 20px;
  border-bottom: 1px solid var(--border); flex-wrap: wrap; gap: 10px;
}
.list-row:last-child { border-bottom: none; }
/* .pill — [GLOBAL, used on 7 pages incl. admin-console.html] */
.pill { font-size: 12px; font-weight: 600; color: var(--text-secondary); background: var(--bg-inset); border-radius: 999px; padding: 3px 10px; }
/* .avatar — [GLOBAL/SHARED: onboarding, report, reset-staff-pin,
   partials/admin-topbar.html] */
.avatar {
  width: 34px; height: 34px; border-radius: 50%; background: var(--bg-inset); color: var(--text-primary);
  font-size: 12px; font-weight: 700; display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
/* .enc-badge — [GLOBAL: index, intake, onboarding, qr-intake] */
.enc-badge {
  font-size: 10px; font-weight: 700; color: var(--success-alt); background: var(--success-bg);
  border-radius: 999px; padding: 2px 7px; margin-left: 6px; text-transform: uppercase;
}
/* .role-chip (+ variants) — [PAGE: onboarding.html only] */
.role-chip { font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: 999px; }
.role-chip.staff { background: var(--bg-inset); color: var(--text-secondary); }
.role-chip.branch_manager { background: rgba(0,99,137,0.14); color: var(--primary); }
.role-chip.zone_manager { background: rgba(111,175,46,0.16); color: var(--success-alt); }
.role-chip.owner { background: var(--warn-bg); color: var(--warn); }
.role-chip.business_admin { background: var(--accent-purple-bg); color: var(--accent-purple); }

/* .pin-chip — [PAGE: onboard-tenant.html only, currently] */
.pin-chip { font-size: 13px; font-weight: 700; color: var(--primary-dark); background: rgba(0,99,137,0.10); border-radius: 8px; padding: 6px 10px; }

/* ============================================================
   22. CONSENT BOX  [SHARED: intake.html, qr-intake.html]
   ============================================================ */
.consent-box { background: var(--bg-inset); border-radius: 10px; padding: 14px; }
.consent-box p { margin: 0 0 10px; font-size: 13px; font-style: italic; color: var(--text-secondary); }
.consent-box label { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; }
.consent-box input[type="checkbox"] { width: 20px; height: 20px; margin-top: 1px; accent-color: var(--primary); flex-shrink: 0; }
.consent-box span.consent-text { font-size: 14px; font-weight: 500; }
.my-qr-wrap { margin-top: 50px;}

/* ============================================================
   23. EMPTY STATES  [SHARED: admin-console.html, onboarding.html]
   ============================================================
   NOTE: .empty-state-title must stay defined AFTER .section-title
   (section 11) — see the file-level "IMPORTANT" note at the top of this
   file for why. */
.empty-state {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 6px; padding: 32px 20px; border: 1.5px dashed var(--border-strong);
  border-radius: 12px; background: var(--bg-inset);
}
.empty-state-icon {
  width: 49px; height: 49px; display: flex; align-items: center; justify-content: center; margin-bottom: 6px;
}
.empty-state-icon img { width: 100%; height: 100%; }
.empty-state-title { font-weight: 700; font-size: 14px; color: var(--text-primary); }
.empty-state-sub { font-size: 13px; color: var(--text-secondary); max-width: 340px; }

/* Body-copy style matching the global `p` rule, as a reusable class for
   spans/inline elements that need the same look (e.g. dashboard empty-state
   captions) without affecting every existing .empty-state-sub usage
   elsewhere (onboarding.html keeps its smaller secondary-caption style).
   Uses var(--text-primary) rather than a literal black so it stays readable
   inside panels whose background adapts to dark mode (e.g. the pending
   branch requests empty state, which sits on var(--bg-inset)). */
/* ============================================================
   24. .section-sub  [GLOBAL utility — currently only consumed by
       admin-console.html, written generically for reuse elsewhere]
   ============================================================ */
.section-sub { font-weight: 400; font-size: 18px; line-height: 28px; letter-spacing: 0.03em; color: var(--text-primary); max-width: none; }

/* [PAGE: admin-console.html] — #tenantList/#leadList are intentionally a fixed light grey (#F2F3F7) in
   both themes to match the stat/ds cards around them — so their title and
   caption text must stay fixed dark too, instead of following
   var(--text-primary)/.section-sub's normal light-in-dark-mode behavior
   (which would otherwise render near-invisible light text on that light
   background once dark mode is on). Covers each row's own title/caption
   too (.list-row-title/.text-tertiary) — those were missed by the original
   fix here, which only caught the empty-state and section-sub text, so a
   populated list still went near-white-on-near-white in dark mode while an
   empty one read fine. */
#tenantList .empty-state-title, #leadList .empty-state-title,
#tenantList .section-sub, #leadList .section-sub,
#tenantList .list-row-title, #leadList .list-row-title {
  color: #101828;
}
#tenantList .text-tertiary, #leadList .text-tertiary {
  color: #475467;
}

/* ============================================================
   25. LOADING SKELETON  [RESERVED — not referenced by any page's markup
       or JS right now]
   ============================================================ */
.skeleton {
  background: linear-gradient(90deg, var(--bg-inset) 25%, var(--border) 37%, var(--bg-inset) 63%);
  background-size: 400% 100%; animation: skeletonWave 1.4s ease infinite; border-radius: 8px;
}
@keyframes skeletonWave { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ============================================================
   25b. SCROLL FADE-IN  [SHARED: every page that loads
        partials/admin-shell-loader.js — admin-console.html (Repzy admin),
        dashboard.html/report.html/send-queue.html/intake.html/my-qr.html/
        reset-staff-pin.html/onboarding.html/staff-profile.html (owner/
        branch_manager/zone_manager/staff), admin-profile.html/
        admin-notifications.html/onboard-tenant.html]
   Class applied by initScrollFadeIn() in admin-shell-loader.js to each
   page's top-level card sections; .in-view is added the first time a
   section crosses into the viewport (IntersectionObserver, one-shot).
   prefers-reduced-motion: users who've asked the OS to cut motion get the
   content at full opacity/position immediately, never the animated version.
   ============================================================ */
.fade-in-section { opacity: 0; transform: translateY(24px); transition: opacity 0.6s ease, transform 0.6s ease; }
.fade-in-section.in-view { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .fade-in-section { opacity: 1; transform: none; transition: none; }
}

/* ============================================================
   26. STATUS BANNER  [GLOBAL — used on 10 pages incl. admin-console.html
       and onboard-tenant.html]
   ============================================================ */
.status-banner {
  display: flex; align-items: flex-start; gap: 10px; padding: 13px 15px; border-radius: 10px;
  font-size: 13px; font-weight: 500; border: 1px solid var(--flag-border); background: var(--flag-bg); color: var(--danger);
}
.status-banner.info { border-color: var(--ai-border); background: var(--ai-bg); color: var(--text-primary); }
.status-banner.success { border-color: var(--success-bg); background: var(--success-bg); color: var(--success-alt); }

/* .tenant-console-onboarding — [PAGE: onboard-tenant.html] marks the info
   banner on the "Onboard a new tenant" form so it gets this larger
   Figma-spec treatment without changing .status-banner.info on any of the
   other 9 pages that use it. */
.status-banner.info.tenant-console-onboarding {
  min-height: 132px;
  background: #EFF8FD;
  border: 1px solid rgba(0, 0, 0, 0.24);
  border-radius: 10px;
  padding: 35px 80px 40px 40px;
  margin-bottom: 24px; 
}
 

/* ============================================================
   27. TOAST  [GLOBAL — not present in any page's static markup, but
       created dynamically by theme.js's showToast() helper, which every
       page loads]
   ============================================================ */
.toast {
  position: fixed; bottom: 28px; left: 50%; transform: translateX(-50%);
  background: var(--text-primary); color: var(--bg-page); padding: 11px 18px; border-radius: 10px;
  font-size: 13px; font-weight: 600; box-shadow: 0 8px 24px rgba(0,0,0,0.25); z-index: 50;
  animation: toastIn 0.2s ease;
}
.toast.error { background: var(--danger); color: #fff; }

/* confirmToast() — theme.js's in-app replacement for window.confirm(),
   built by that function on demand (not present in any page's markup).
   Dims the page behind it (same intent as this app's existing tenant/lead
   detail-modal overlays: block the rest of the page from being clicked
   while a yes/no decision on a real action is pending) rather than
   floating as a passive, non-blocking corner card like .toast above — see
   the comment on confirmToast() in theme.js for why. z-index sits above
   .toast (50) so a success/error toast fired right after confirming isn't
   hidden behind a backdrop that's already animating out. */
.toast-confirm-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,0.45);
  display: flex; align-items: center; justify-content: center;
  z-index: 200; animation: confirmFadeIn 0.15s ease;
}
.toast-confirm {
  background: var(--bg-surface); color: var(--text-primary); border: 1px solid var(--border);
  border-radius: 14px; padding: 20px; max-width: 380px; width: calc(100% - 48px);
  box-shadow: 0 16px 40px rgba(0,0,0,0.3);
  animation: confirmFadeIn 0.15s ease;
}
.toast-confirm-message { margin: 0 0 18px; font-size: 14px; line-height: 1.5; color: var(--text-primary); }
.toast-confirm-actions { display: flex; justify-content: flex-end; gap: 10px; }
.toast-confirm-actions .btn-secondary-sm, .toast-confirm-actions .btn-primary-sm, .toast-confirm-actions .btn-danger-sm {
  width: auto;
}

/* Paragraph variant of .text-tertiary used for helper/caption copy inside
   admin-console.html cards and the tenant-detail modal. Scoped under
   .admin-shell (rather than redefining p.text-tertiary globally) since
   .text-tertiary is also used as inline caption text with different sizing
   on several other screens (onboarding.html, report.html, etc.). */
.admin-shell p.text-tertiary { font-size: 12px; margin: 4px 0 8px; }

/* ============================================================
   28. ADMIN CONSOLE SHELL (sidebar + topbar + all responsive breakpoints)
       [PAGE: admin-console.html, onboard-tenant.html,
        partials/admin-sidebar.html, partials/admin-topbar.html — treated
        as one unit since the partials only ever render inside these two
        pages' .admin-shell wrapper]

   Scoped to the admin console via the admin- prefix so it can't affect any
   other screen that shares this stylesheet. Everything from here down belongs to this one unit's base (non-responsive)
   layout — if you're editing the admin sidebar, topbar, or stat/AI card
   layout, it's all here. Its 1300px->320px responsive breakpoints now
   live in responsive.css (extracted from here), not in this file. */
.admin-shell, #detailModalOverlay {
  --primary: #0042D1;
  --primary-dark: #0036AB;
  --primary-focus: rgba(0, 66, 209, 0.18);
}
/* Figma-matched blue for the Repzy admin console only. Scoped here (rather
   than in :root) since --primary/--primary-dark/--primary-focus cascade
   down to every descendant exactly like a :root override would, but only
   within these two subtrees — every other screen keeps its current teal
   look. #detailModalOverlay is included alongside .admin-shell (not just
   nested under it) because admin-console.html/admin-management.html/
   admin-notifications.html all render its #detailModalCard content as a
   sibling of .admin-shell, not a descendant — without this, any
   var(--primary)-based button in a modal (e.g. .btn-primary-sm) falls back
   to the default teal instead of matching the rest of the console, same bug
   #detailModalCard .btn-primary below (line ~644) was hardcoded to work
   around before --primary was scoped this way. */
.admin-shell {
  display: flex; min-height: 100vh; align-items: flex-start; background: var(--bg-page);
}
.admin-sidebar {
  width: 378px; flex-shrink: 0; background: var(--bg-surface);
  display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh; z-index: 30;
  transition: transform 0.2s ease; padding-right: 27px;
    box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.05);
}
.admin-sidebar-brand { padding: 40px; padding-bottom: 20px; position: relative; }
.admin-sidebar-brand img { height: 100px; display: block; }
/* The logo links to the dashboard (dashboard.html for tenant staff,
   admin-console.html for Repzy admin — see the two sidebar partials) — sized
   to the image itself, not the full sidebar width, and with no default link
   underline/color since the image already communicates it's clickable. */
.admin-sidebar-brand a { display: block; width: fit-content; }
.admin-icon-btn.admin-sidebar-close {
  display: none; position: absolute; top: 16px; right: 0;
  width: 32px; height: 32px; flex-shrink: 0; z-index: 1;
}
.admin-icon-btn.admin-sidebar-close svg { width: 14px; height: 14px; }
.admin-nav { display: flex; flex-direction: column; gap: 22px; padding: 16px 0; }
.admin-nav-item {
  display: flex; align-items: center; gap: 13px; min-height: 74px; padding: 19px 50px;
  font-size: 20px; font-weight: 700; line-height: 34px; letter-spacing: 0.03em; text-transform: capitalize;
  color: var(--text-primary); cursor: pointer; border: none; border-bottom: 1px solid rgba(0,0,0,0.09);
  background: transparent; text-align: left; width: 100%; font-family: inherit;
  border-radius: 0 36.5px 36.5px 0;
  transition: background 0.15s ease, color 0.15s ease;
}
.admin-nav-item svg { flex-shrink: 0; width: 28px; height: 28px; }
.admin-nav-item:hover { background: var(--bg-inset); color: var(--text-primary); }
/* Same pill shape as .admin-nav-item's base rule above (now shared by every
   state), tinted with --primary-focus (brand primary at 18% alpha — see the
   :root definition + public/brand.js) so this follows a tenant's own brand
   color once set. Scoped to body.tenant-console (set by
   admin-shell-loader.js) — .admin-nav-item is also used by the Repzy admin
   console's own sidebar (admin-sidebar.html), which keeps the plain
   --bg-inset hover above regardless of which tenant's colors an admin
   happens to be viewing. */
body.tenant-console .admin-nav-item:hover {
  background: var(--primary-focus); color: var(--text-primary);
}
.admin-nav-item.active {
  background: var(--admin-nav-active-bg); color: var(--admin-nav-active-text);
}
.admin-nav-item:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.admin-sidebar-backdrop { display: none; }

.admin-main { flex: 1; min-width: 0; }
.admin-topbar {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  padding: 27px 80px 0 45px
}
.admin-topbar-header {
        padding-top: 0;
        /* Without a cap, a long subtitle (e.g. reset-staff-pin.html's) makes
           the browser size this flex item to fit the text on one line,
           leaving no room for .admin-topbar-actions on the same row — it
           wraps below and (even with the margin-left:auto fix above)
           lands noticeably lower than the title instead of tucked
           top-right beside it. The narrow media-query overrides below
           fine-tune this per breakpoint for pixel-matched widths; this is
           the always-on fallback so any viewport width (including gaps
           between those breakpoints) stays safe.
           60% (measured, not a round-number guess) still wasn't tight
           enough: on reset-staff-pin.html's 3-line subtitle plus a
           longer-than-average signed-in name (e.g. "Hamara Choice
           Jewellers Zone Manager"), the header alone claimed ~850px at a
           1920px viewport — 13px more than the ~1417px of content width
           actually left room for once the actions block (~565px) and
           their 16px gap were accounted for, forcing an unwanted wrap
           even on a full-width desktop window. 55% claws back enough of
           that margin to keep this pairing on one line. */
        max-width: 55%;
}
.admin-page-title {
  font-size: 24px; font-weight: 700; letter-spacing: 0.03em; margin: 0; line-height: 34px;
  color: var(--text-primary); text-transform: uppercase;
}
.admin-back-link {
  display: inline-flex; align-items: center; gap: 14px;
  padding-left: 0; margin: 0 0 6px;
  font-weight: 600; font-size: 18px; line-height: 27px; letter-spacing: 0.03em;
  text-transform: capitalize; color: var(--text-secondary);
}
/* margin-left:auto — several responsive.css breakpoints (993px–1399px)
   force .admin-topbar-header to width:100%, leaving no room for this
   block beside it and wrapping it onto its own line below. .admin-topbar's
   justify-content:space-between only positions two-or-more items on a
   line; with this as the sole item on its wrapped line, browsers fall
   back to flex-start (pins it to the left) instead. margin-left:auto
   consumes all the leftover space as margin before this element instead,
   which pins it to the right in both the wrapped and unwrapped case — so
   it belongs here at the base rule rather than patched into each
   breakpoint individually. Single row (not the old flex-direction:column
   stack) — theme toggle/bell/account chip and sign-out/onboard now all sit
   on the same line, same top-right cluster tenant-console pages already
   show (those just have fewer items in it, since primaryAction is null
   there), instead of wrapping onto a visually separate second row. */
.admin-topbar-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-left: auto; }
.admin-topbar-actions-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* #topbarPrimaryAction ("Onboard a tenant") — every tenant-console page sets
   SHELL_CONFIG.primaryAction to null (see admin-shell-loader.js), which
   hides this button entirely, so it only ever renders on Repzy admin pages.
   Kept on the fixed Repzy blue rather than var(--primary)/var(--primary-dark)
   for that reason — there's no tenant-console case where brand color would
   apply here. */
.admin-topbar .btn-primary {
  display: inline-flex; align-items: center; gap: 8px;
  background: #0042D1; border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 29.5px;
  padding: 7px 15px; font-weight: 500; font-size: 20px; line-height: 34px; letter-spacing: 0.03em; text-transform: none;
  color: #FFFFFF;
}
.admin-topbar .btn-primary:hover { box-shadow: 0 4px 12px rgba(0, 66, 209, 0.3); }
.admin-topbar p {
  font-weight: 400; font-size: 18px; line-height: 27px; letter-spacing: 0.03em;
  color: var(--text-secondary); margin-top: 10px; margin-bottom: 0;
}

.admin-icon-btn {
  width: 60px; height: 60px; border-radius: 999px; border: 1px solid rgb(0 0 0 / 15%); background: var(--bg-surface);
  color: var(--text-secondary); display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  flex-shrink: 0; padding: 0;
}
.admin-icon-btn svg { width: 24px; height: 24px; }
.admin-icon-btn:hover { background: var(--bg-inset); color: var(--text-primary); }
.admin-icon-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* Icon-only variant of #topbarPrimaryAction ("Onboard a tenant") — same
   circular sizing as the plain .admin-icon-btn buttons beside it (theme
   toggle, bell, sign-out), so the whole action cluster reads as one row of
   equal-size icon buttons, just on the fixed Repzy blue to keep it visually
   the primary action of the group. */
.admin-icon-btn-primary { background: #0042D1; border: none; color: #FFFFFF; }
.admin-icon-btn-primary:hover { background: #0036AB; color: #FFFFFF; }
.admin-admin-chip {
  display: flex; align-items: center; gap: 8px; padding: 4px 10px 4px 4px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--bg-surface);
}
/* Equal padding on every side (not the old icon+text 6px/14px split) and a
   fixed square size — now that the chip holds only the avatar (name/role
   text removed), asymmetric padding left it a 64x56 box, which
   border-radius:999px rounds into an oval rather than a true circle.
   60x60 also matches the other topbar icon buttons beside it exactly. */
.admin-admin-chip { width: 60px; height: 60px; padding: 0; justify-content: center; gap: 10px; border: 1px solid rgb(0 0 0 / 15%); }
.admin-admin-chip .avatar { width: 26px; height: 26px; font-size: 11px; }
.admin-admin-chip .avatar { width: 44px; height: 44px; font-size: 18px; }
.admin-admin-chip-text { display: flex; flex-direction: column; line-height: 1.3; }
.admin-admin-role { font-size: 11px; color: var(--text-tertiary); }
.admin-chip-chevron { color: var(--text-tertiary); flex-shrink: 0; }
#adminName { font-size: 18px; line-height: 32px; font-weight: 500; color: var(--text-primary); }
.btn-signout {
  padding: 8px 16px; background: var(--bg-surface); border: 1px solid var(--border-strong); border-radius: 29.5px;
  font-style: normal; font-weight: 500; font-size: 20px; line-height: 34px; letter-spacing: 0.03em;
  color: var(--text-primary); cursor: pointer;
}
.btn-signout:hover { background: var(--bg-inset); color: #0042d1; }

/* ---- Notifications bell (dropdown preview of admin-notifications.html) ---- */
.notif-badge {
  position: absolute; top: 0px; right: 12px; min-width: 19px; height: 19px; padding: 0 4px;
  border-radius: 999px; background: #F33434; color: #fff; font-size: 12px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; line-height: 1; pointer-events: none;
}
.notif-dropdown {
  position: absolute; top: calc(100% + 10px); right: 0; width: 340px; max-width: 90vw;
  background: var(--bg-surface); border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow);
  z-index: 50; overflow: hidden;
}
.notif-dropdown-header { padding: 14px 16px 10px; border-bottom: 1px solid var(--border); }
.notif-dropdown-list { max-height: 360px; overflow-y: auto; }
.notif-row { display: flex; flex-direction: column; gap: 2px; padding: 12px 16px; border-bottom: 1px solid var(--border); }
.notif-row:last-child { border-bottom: none; }
.notif-row-title { font-weight: 600; font-size: 13px; color: var(--text-primary); }
.notif-row-detail { font-size: 12px; color: var(--text-tertiary); }
.notif-dropdown-footer {
  display: block; text-align: center; padding: 12px; font-size: 13px; font-weight: 600;
  color: var(--primary); text-decoration: none; border-top: 1px solid var(--border);
}
.notif-dropdown-footer:hover { background: var(--bg-inset); }

/* Plain menu item — reuses .notif-dropdown's floating-panel shell (position/
   background/border/shadow, nothing notification-specific despite the
   name) for any small click-to-pick menu, e.g. the Tenant performance
   day-window filter. */
.dropdown-menu-item {
  display: block; width: 100%; text-align: left; padding: 10px 16px; font-size: 13px; font-weight: 500;
  color: var(--text-primary); background: none; border: none; border-top: 1px solid var(--border); cursor: pointer;
}
.dropdown-menu-item:first-child { border-top: none; }
.dropdown-menu-item:hover { background: var(--bg-inset); }
.admin-content { padding: 20px 80px 64px 45px; max-width: 100%; margin-top: 50px; }
.admin-mobile-toggle { display: none; }


.card-header-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 4px; flex-wrap: wrap; }
.card-dropdown-label {
  display: inline-flex; align-items: center; gap: 8px; background: var(--bg-surface); border: 1px solid var(--border-strong);
  border-radius: 29.5px; padding: 10px 23px; font-weight: 400; font-size: 18px; line-height: 28px;
  letter-spacing: 0.03em; text-transform: capitalize; color: var(--text-primary);
}
.card-dropdown-label img { width: 14px; height: 7px; }

.stat-icon-chip {
  width: 66px; height: 66px; border-radius: 9999px; flex-shrink: 0; display: block;
}

.pill-new { background: var(--ai-bg); color: var(--primary); }
.pill-contacted { background: var(--warn-bg); color: var(--warn); }
.pill-declined { background: var(--flag-bg); color: var(--danger); }
.pill-converted { background: var(--success-bg); color: var(--success-alt); }

/************************ Onboard Tenant**********************************************/

.tenant-console-onboarding-wrap.admin-content  { margin-top: 26px; padding-top: 0; }

/* [PAGES: onboard-tenant.html (Repzy admin) AND onboarding.html (tenant
   owner's Business Settings)] — the form card inside the onboarding wrap.
   Scoped via .tenant-console-onboarding-wrap so it doesn't affect .ds-card
   anywhere else (12 other pages use that class). */
.tenant-console-onboarding-wrap .ds-card {
  background: var(--bg-surface);
  box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.15);
  border-radius: 10px;
  padding: 50px 160px;
  border: none;
  transition: box-shadow 0.2s ease;
}
/* Brand-color hover glow — scoped to body.tenant-console (set by
   admin-shell-loader.js when SHELL_CONFIG.sidebarPartial is
   dashboard-sidebar.html) so it only applies on onboarding.html (tenant
   owner), not onboard-tenant.html (Repzy admin), which shares this same
   .ds-card markup but stays on the flat shadow above — same
   admin-vs-tenant split as .admin-nav-item/.stat-card/.admin-form buttons
   elsewhere in this file. Same --card-hover-glow token (brand primary at
   40% alpha — see the :root definition + public/brand.js) as .ds-card:hover
   and .ds-card.report-panel(-spaced):hover. */
body.tenant-console .tenant-console-onboarding-wrap .ds-card:hover {
  box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.15), 0 0 24px var(--card-hover-glow);
}

/* [PAGE: intake.html] — same card treatment (shadow/radius/no-border) as
   onboard-tenant.html's .admin-form card above, scoped separately since
   intake's form is much narrower (3 fields, meant to be filled in seconds
   at a counter) — 160px side padding would leave almost no room for input
   width at that size, so this uses its own proportionally smaller padding
   and a wider wrap-inner cap (560px vs the default 440px) to give the
   larger pill inputs room to breathe. */
.intake-form-wrap .wrap-inner.wide { padding: 0px 80px 64px 45px; max-width: 100%; } 
.intake-form-wrap .ds-card {
  background: var(--bg-surface);
  box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.15);
  border-radius: 10px;
  padding: 50px 160px;
  border: none;
}
#intakeForm .card-title { margin: 0;}


/* [PAGE: send-queue.html] — same shadow/radius/no-border card treatment as
   the two above, but padding sized for a data table (needs its columns'
   width, not a narrow form's breathing room) rather than reusing
   onboard-tenant's 160px form padding. */
.send-queue-wrap .ds-card {
  background: var(--bg-surface);
  box-shadow: 0px 26px 62px rgba(0, 0, 0, 0.15);
  border-radius: 10px;
  padding: 24px;
  border: none;
}

/* [PAGE: reset-staff-pin.html] — same shadow/radius/no-border treatment as
   the three .ds-card wraps above, applied to this page's own .reset-modal
   (a bespoke multi-step wizard card, not .ds-card, so it gets its own
   scoped override instead). The .reset-step sections also carry the
   .admin-form class directly in the markup — .reset-step's own layout
   (flex column, gap:16px) already matches .admin-form's, so that one class
   addition is enough to pick up the same pill inputs/buttons as
   onboard-tenant.html, no markup restructuring needed.

   Everything below, down to .return-search-btn, used to live in a page-only
   <style> block in reset-staff-pin.html's own <head> — moved here so this
   page carries no CSS of its own, matching every other page. Left as plain
   top-level selectors (not nested under .reset-pin-wrap) the same way
   .hub-card/.ds-table are elsewhere in this file: these class names are
   bespoke enough that a global collision isn't a real risk. The handful of
   classes after .center-col (.staff-list-wrap, .staff-list-label,
   .staff-list-empty, .confirm-name, .confirm-lead-text, .success-title,
   .success-sub, .return-search-btn) replace what used to be inline
   style="" attributes in the markup/JS template strings — same reasoning,
   this page shouldn't carry styling outside theme.css either. */
 
.reset-modal { max-width: 560px; margin: 40px auto; overflow: hidden; }
.reset-modal-header {
  padding: 20px 22px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between;
}
.reset-modal-title { font-size: 20px; font-weight: 700; margin: 0; color: var(--text-primary); }
.reset-modal-sub { font-size: 12px; color: var(--text-secondary); margin: 3px 0 0; display: flex; align-items: center; gap: 4px; }
.encrypted-pill {
  font-size: 11px; font-weight: 700; color: var(--success-alt); background: var(--success-bg);
  border-radius: 999px; padding: 4px 10px; display: flex; align-items: center; gap: 5px; flex-shrink: 0;
}
.reset-step { padding: 22px; display: flex; flex-direction: column; gap: 16px; }
.reset-step.hidden { display: none; }
.search-wrap { position: relative; }
.search-wrap .ds-input { padding-right: 40px; }
.search-icon {
  position: absolute; right: 14px; top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; color: var(--text-tertiary); pointer-events: none;
}
.staff-list-wrap { display: flex; flex-direction: column; gap: 8px; }
.staff-list-label { font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
.staff-list-empty { padding: 10px 0; }
#list { display: flex; flex-direction: column; gap: 8px; }
.staff-pick-row {
  display: flex; align-items: center; gap: 12px; width: 100%; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--bg-surface);
  /* color: explicit, not just inherited — this is a <button>, and form
     controls don't inherit color from ancestors like other elements do
     (they use the UA's own default instead). Without this, .staff-pick-name
     below falls back to that default rather than following the theme,
     rendering as low-contrast dark text on dark mode's dark row background. */
  color: var(--text-primary);
  cursor: pointer; text-align: left; transition: all 0.15s ease;
}
.staff-pick-row:hover { border-color: var(--primary); background: var(--bg-inset); }
.staff-pick-row .chevron { margin-left: auto; }
.staff-pick-name { font-weight: 600; font-size: 14px; display: block; }
.confirm-person {
  display: flex; align-items: center; gap: 12px; background: var(--bg-inset);
  border: 1px solid var(--border); border-radius: 10px; padding: 14px;
}
.confirm-avatar { width: 44px; height: 44px; font-size: 14px; }
.confirm-name { font-weight: 700; font-size: 15px; display: block; }
.confirm-lead-text { margin: 0; font-size: 14px; color: var(--text-primary); }
.notice-box { font-size: 13px; color: var(--text-secondary); background: var(--bg-inset); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; }
.step-actions { display: flex; gap: 10px; padding-top: 4px; }
.step-actions .btn-primary { flex: 1; }
.step-actions .btn-secondary-sm { flex: 1; text-align: center; padding: 12px; }
.custom-pin-toggle { font-size: 12px; font-weight: 600; color: var(--primary); background: none; border: none; cursor: pointer; padding: 0; text-align: left; }
.success-icon {
  width: 56px; height: 56px; border-radius: 50%; background: var(--success-bg); color: var(--success-alt);
  display: flex; align-items: center; justify-content: center; font-size: 26px; margin: 0 auto 4px;
}
.success-title { margin: 0; font-size: 18px; font-weight: 700; color: var(--text-primary); }
.success-sub { margin: 4px 0 0; font-size: 13px; }
.pin-reveal {
  width: 100%; background: var(--bg-inset); border: 2px solid var(--primary); border-radius: 12px;
  padding: 16px 18px; display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.pin-reveal-value { font-size: 34px; font-weight: 800; letter-spacing: 0.15em; color: var(--primary); font-family: 'SFMono-Regular', Consolas, monospace; }
.copy-btn {
  width: 40px; height: 40px; border-radius: 8px; border: 1px solid var(--border); background: var(--bg-surface);
  color: var(--primary); cursor: pointer; font-size: 12px; font-weight: 700; flex-shrink: 0; letter-spacing: 0.03em;
}
.copy-btn.copied { background: var(--success); color: #fff; border-color: var(--success); }
.sent-note { font-size: 12px; color: var(--text-secondary); background: var(--bg-inset); border-radius: 999px; padding: 6px 12px; text-align: center; }
.audit-line {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  padding-top: 12px; border-top: 1px solid var(--border); font-size: 12px; color: var(--text-tertiary);
}
.center-col { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px; }
.return-search-btn { width: 100%; padding: 11px; }

.reset-pin-wrap .reset-modal { margin: 0px auto; max-width: 100%; }




/* Widen this page's own content column to fill the available width instead
   of the shared .page-inner's 1080px cap (section 4) — .reset-modal itself
   still caps at 560px and centers via margin:auto, so this only changes how
   much breathing room surrounds the wizard, not the wizard's own width. */
.reset-pin-wrap { max-width: 100%; }

/* [SHARED — reusable "admin dashboard form" component] — apply .admin-form
   to any <form> in the admin dashboard (admin-console.html or
   onboard-tenant.html) that wants this larger field/label/button
   treatment. Currently only onboard-tenant.html's #onboardTenantForm uses
   it. Deliberately scoped by .admin-form (not bare label.field-label/
   .ds-input/.btn-primary/.card-title) so it does NOT change the existing
   compact modal forms already on admin-console.html (renewal payment,
   lead status/notes, tenant subdomain/review-link editors) — those keep
   the smaller base field-label/ds-input styles from sections 6/7. */
.admin-form { display: flex; flex-direction: column; gap: 16px; }
.admin-form .card-title {
  font-weight: 700; font-size: 20px; line-height: 34px; letter-spacing: 0.03em;
  text-transform: uppercase; color: var(--text-primary); margin-bottom: 15px;
}
.admin-form label.field-label {
  font-weight: 400; font-size: 18px; line-height: 27px; letter-spacing: 0.03em; color: var(--text-primary);
}
.admin-form .ds-input, .admin-form select.ds-input {
  background: var(--bg-surface); border: 1px solid var(--border-strong); border-radius: 29.5px;
  min-height: 56px; padding: 14px 25px; width: 100%;
  outline: none;
    box-shadow: none;
}
/* Selects — swap the browser's native arrow for assets/down_arrow_select.svg
   and mute the text/option color to #7D7D7D (matches the placeholder-style
   look in the Figma reference for both real placeholder options like
   "Select a plan…" and the pre-filled default like "Driving School"). */
.admin-form select.ds-input {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  background-image: url('/assets/down_arrow_select.svg');
  background-repeat: no-repeat;
  background-position: right 25px center;
  background-size: 14px 7px;
  padding-right: 55px;
  color: #7D7D7D;
}
.admin-form select.ds-input option { color: #7D7D7D; }

/* File input (Logo upload) — style the input as the same pill, and style
   the native "Choose File" control (::file-selector-button, with the
   -webkit- fallback for older Chrome/Safari) as a small grey chip inset
   inside it, matching the Figma reference. */
.admin-form input[type="file"].ds-input {
  display: flex; align-items: center;
  padding: 8px 11px; color: #7D7D7D; overflow: hidden;
}
.admin-form input[type="file"].ds-input::file-selector-button {
  background: var(--bg-inset); border: none; border-radius: 19px;
  padding: 9px 20px; margin-right: 19px; font-size: 18px; line-height: 27px;
  letter-spacing: 0.03em; color: var(--text-primary); cursor: pointer; flex-shrink: 0; border: 1px solid var(--border); min-height: 38px;
}
.admin-form input[type="file"].ds-input::-webkit-file-upload-button {
  background: var(--bg-inset); border: none; border-radius: 19px;
  padding: 9px 20px; margin-right: 19px; font-size: 18px; line-height: 27px;
  letter-spacing: 0.03em; color: var(--text-primary); cursor: pointer; flex-shrink: 0; border: 1px solid var(--border); min-height: 38px;
}

/* Two-field row layout for .admin-form — not nested under .admin-form in
   the selector since it's a generic grid helper, but only ever used
   inside one today. */
.admin-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 27px; }
/* .admin-form is shared by both onboard-tenant.html (Repzy admin) and
   intake.html/onboarding.html/reset-staff-pin.html (tenant-console) — fixed
   Repzy blue by default; body.tenant-console below switches it to the
   tenant's own brand color on the pages where that applies. */
.admin-form #submitBtn, .admin-form .btn-primary {
  background: #0042D1; border-radius: 29.5px; min-height: 56px;
  font-weight: 700; font-size: 18px; line-height: 34px; letter-spacing: 0.03em;
  text-transform: uppercase; color: #FFFFFF;
  cursor: pointer; transition: background 0.15s ease, box-shadow 0.15s ease; padding: 12px 25px;
}
/* Explicit hover/disabled states here (rather than relying on the base
   .btn-primary:hover/:disabled rules from section 7) since this rule's
   higher specificity (.admin-form .btn-primary / #submitBtn) would
   otherwise silently win over those and cancel the hover effect. */
.admin-form #submitBtn:hover, .admin-form .btn-primary:hover {
  background: #0036AB; box-shadow: 0 4px 12px rgba(0, 66, 209, 0.3);
}
.admin-form #submitBtn:disabled, .admin-form .btn-primary:disabled {
  cursor: default; background: #0042D1; box-shadow: none;
}
body.tenant-console .admin-form #submitBtn, body.tenant-console .admin-form .btn-primary {
  background: var(--primary);
}
body.tenant-console .admin-form #submitBtn:hover, body.tenant-console .admin-form .btn-primary:hover {
  background: var(--primary-dark); box-shadow: 0 4px 12px var(--primary-glow);
}
body.tenant-console .admin-form #submitBtn:disabled, body.tenant-console .admin-form .btn-primary:disabled {
  background: var(--primary);
}

.ds-input-repzy-tech { width: 90%; }
.text-tertiary-fields { 
  font-weight: 400;
  font-size: 18px;
  line-height: 27px;
  letter-spacing: 0.03em;
  text-transform: lowercase;
  color: #7D7D7D;
}

#notificationsDropdownList .empty-state { border-radius: 0;}
.admin-admin-chip:hover, .admin-admin-chip:focus { border: 1px solid rgb(0 0 0 / 26%); background: var(--bg-inset);} 
  
/* ============================================================
   29. UTILITY  [GLOBAL — .hidden used on virtually every page incl.
       admin-console/onboard-tenant; .spinner currently intake.html only
       but a generic reusable primitive]
   ============================================================ */
.hidden { display: none !important; }
.spinner {
  display: inline-block; width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.4); border-top-color: #fff;
  animation: spin 0.7s linear infinite; vertical-align: middle; margin-right: 8px;
}

/* ============================================================
   30. REPORT PAGE  [PAGE: report.html — filters row, custom date range,
       list-column layout helpers, callouts (top performer / needs
       coaching), staff leaderboard, rating-tier legend. Moved out of
       report.html's own <style> block + inline style="" attributes so
       every page's CSS lives in this one file; see sections 10/14/17/18/
       19/21 above for the report.html variants added to already-shared
       components (ds-card, stat-value, bar-fill, trend-wrap, avatar).]
   ============================================================ */
.report-filters-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-bottom: 22px; }
.ds-input.ds-input-auto { width: auto; }
.custom-range-row { display: flex; gap: 8px; align-items: center; margin: -10px 0 22px; }
.date-input-sm { width: 150px; }

.report-list-col { display: flex; flex-direction: column; gap: 25px; margin-top: 37px; }
.leaderboard-list { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.report-api-note { margin-top: 30px; }

.callouts-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 20px; }

.callout-card { border-radius: 12px; padding: 30px; border: 1px solid; min-height: 160px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start; }
.callout-good { background: var(--success-bg); border-color: rgba(22,163,74,0.3); }
.callout-warn { background: var(--warn-bg); border-color: rgba(181,71,8,0.3); }
/* Same brand teal used by .ai-card/.pill-new — for callouts that are a
   highlight rather than a status (e.g. "Business of the Month"), where
   the green/amber of .callout-good/-warn would misread as success/warning. */
.callout-brand { background: var(--ai-bg); border-color: var(--ai-border); }
.callout-tag {
  display: inline-flex; align-items: center; gap: 5px;
  font-weight: 700; font-size: 15px; line-height: 34px; letter-spacing: 0.03em; text-transform: uppercase;
}
.callout-tag-icon { width: 14px; height: 14px; flex-shrink: 0; }
.callout-good .callout-tag { color: var(--success); }
.callout-warn .callout-tag { color: var(--warn); }
.callout-brand .callout-tag { color: var(--primary); }
.callout-body { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.callout-name { font-weight: 700; font-size: 16px; line-height: 34px; letter-spacing: 0.03em; text-transform: uppercase; color: var(--text-primary); }
.callout-meta { font-weight: 400; font-size: 18px; line-height: 28px; letter-spacing: 0.03em; color: var(--text-primary); margin: 0; }

/* Avatar column widened 34px->52px to match .leaderboard-list .avatar's new
   52px size below (avoids clipping the now-larger circle). CTR column
   widened 70px->92px + white-space:nowrap on .lb-ctr below, since "67% CTR"
   at the new 16px size no longer fit on one line in the old 70px column and
   was wrapping to two lines. */
.lb-row { display: grid; grid-template-columns: 20px 52px 130px 1fr 92px 56px; align-items: center;
  gap: 20px; padding: 11px 24px; border-radius: 9px; position: relative;
  background: var(--bg-surface); border-width: 1px 0px; border-style: solid; border-color: var(--border); }
.lb-row-good { background: var(--success-bg); }
.lb-row-warn { background: var(--warn-bg); }
.lb-rank { font-weight: 700; color: var(--text-tertiary); font-size: 13px; }
.leaderboard-list .avatar { width: 52px; height: 52px; }
.lb-name { font-weight: 400; font-size: 16px; line-height: 27px; letter-spacing: 0.03em; text-transform: capitalize; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* width: min(720px, 100% - 180px) instead of width:720px + max-width:100%
   — the previous version capped the bar's own box at 100% of the track but
   then added the two 90px margins on top of that, so bar+margins together
   exceeded the track width and overflowed it, throwing off every column
   after it (this was the main cause of the broken-looking row). This
   version reserves the 180px of margin inside the 100% calc up front, so
   bar+margins can never exceed the track. */
.lb-bar { display: flex; height: 8px; border-radius: 6px; width: min(720px, calc(100% - 180px)); margin: 0 90px; overflow: hidden; background: var(--bg-inset); gap: 2px; cursor: default; }
.lb-bar > div { width: var(--w, 0%); }
.lb-bar > div:first-child { border-radius: 6px 0 0 6px; }
.lb-bar > div:last-child { border-radius: 0 6px 6px 0; }
.lb-seg-5star { background: var(--success); }
.lb-seg-4star { background: var(--success-alt); }
.lb-seg-3star { background: var(--warn); }
.lb-seg-12star { background: var(--danger); }
.lb-bar > .lb-seg-empty { width: 100%; background: var(--border); }
.lb-ctr { font-weight: 400; font-size: 16px; line-height: 27px; letter-spacing: 0.03em; text-transform: capitalize; color: var(--text-primary); text-align: right; white-space: nowrap; }
.lb-fivestar { font-size: 13px; font-weight: 700; color: var(--success); text-align: right; white-space: nowrap; }


.legend-row { display: flex; gap: 14px; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border);
  font-size: 11px; color: var(--text-tertiary); flex-wrap: wrap; }
.legend-swatch { display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 4px; }
.legend-swatch-5star { background: var(--success); }
.legend-swatch-4star { background: var(--success-alt); }
.legend-swatch-3star { background: var(--warn); }
.legend-swatch-12star { background: var(--danger); }

.onboarding-admin .ds-card .card-title { margin-bottom: 0; }
#onboardForm { margin-top: 0; }
#complianceCard, #locationsCard, #staffCard, #templatesCard, #zonesCard { margin-top: 30px; }
/* Branch/zone checkbox rows (Add Zone's branch picker, each zone's own edit
   form, Add Staff's zone picker) — a bordered, hoverable row instead of a
   bare inline checkbox+label, so a multi-item checklist reads as a set of
   selectable options rather than a cramped list of form controls. */
.ds-checkbox-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; border: 1px solid var(--border); border-radius: 10px;
  font-weight: 400; font-size: 14px; color: var(--text-primary);
  cursor: pointer; transition: border-color 0.15s ease, background 0.15s ease;
}
.ds-checkbox-row:hover { border-color: var(--primary); background: var(--bg-inset); }
.ds-checkbox-row input[type="checkbox"] {
  width: 18px; height: 18px; accent-color: var(--primary); cursor: pointer; flex-shrink: 0;
}
#locationList .list-row .list-row-title { font-size: 16px; line-height: 27px; letter-spacing: 0.03em; text-transform: capitalize; color: var(--text-primary); display: block;}

/* ============================================================
   31. ADMIN PROFILE PAGE  [PAGE: admin-profile.html]
       Moved out of admin-profile.html's inline style="" attributes so
       every page's CSS lives in this one file, matching the treatment
       report.html got earlier. Also fixes two real bugs found along the
       way: the account-summary values (name/email/phone/role) were using
       .stat-value's inherited color: var(--text-tertiary) — the muted/
       secondary color meant for de-emphasized text, not the primary data
       on the page — and the inherited text-transform: uppercase made an
       email address render as e.g. "SUPERADMIN@REPZY.TECH", which is both
       unconventional for an email and wider than the plain-case text,
       crowding the card. .profile-stat-value fixes the color for all four
       fields; .profile-stat-email turns off the uppercase + adds a
       word-break safety net, scoped to just the email field so
       name/phone/role keep the uppercase treatment that matches the rest
       of the app. */
/* Overrides .stat-grid's repeat(auto-fit, minmax(180px, 1fr)) with a fixed
   4-column grid: exactly 4 cards per row (Name/Email/Phone/Role), remaining
   cards (Assignment/Customers captured/Status, or fewer on admin-profile.html/
   staff-profile.html's 4-field variant) wrap to their own row rather than
   auto-fit deciding the count from available width. Still responsive.css's
   repeat(2, 1fr)/repeat(1, 1fr) .stat-grid breakpoints below ~1300px/560px,
   same as every other .stat-grid page. */
.profile-stat-grid { grid-template-columns: repeat(4, 1fr); margin-bottom: 16px; }
/* Grid items default to min-width:auto, which sets their automatic minimum
   size to their own min-content width — for a card whose value is a long
   unbroken run (e.g. the email), that can exceed its fr share and force
   that one column a few px wider than its siblings. min-width:0 removes
   that floor so every column truly divides the row equally. */
.profile-stat-grid .stat-card { min-width: 0; }
/* Label-on-top/value-below via .stat-text (section 14) — .stat-card's own
   flex-direction:row is for icon-chip layouts (admin-console.html); this
   page has no icon, so its .stat-text is the card's only child and stacks
   on its own. font-size/line-height override .stat-value's 40px/34px
   defaults (sized for big dashboard numbers), which is why the previous
   18px-only override still rendered with 34px of line-height between
   wrapped lines. */
.stat-value.profile-stat-value { font-size: 13px; line-height: 20px; color: var(--stat-blue); }
.stat-value.profile-stat-email { text-transform: none; overflow-wrap: break-word; }

.ds-card.profile-panel { padding: 24px; }
.profile-header-row { display: flex; align-items: center; gap: 16px; margin-top: 16px; }
.avatar.profile-avatar-lg { width: 72px; height: 72px; font-size: 24px; }
.profile-name-heading { font-size: 20px; font-weight: 800; margin: 0; color: var(--text-primary); }
.profile-divider { border-top: 1px solid var(--border); margin: 20px 0; }
.profile-note { font-size: 13px; margin: 0; }

.profile-form { display: flex; flex-direction: column; gap: 14px; margin-top: 16px; }
/* Visually-hidden "username" field for password-manager autofill — see
   admin-profile.html's comment above this field for why it exists. */
.profile-username-hint {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.pw-field-wrap { position: relative; }
.ds-input.pw-input { padding-right: 44px; }
.toggle-pw-btn {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  background: none; border: none; color: var(--text-tertiary); cursor: pointer; font-size: 12px; font-weight: 600;
  letter-spacing: 0.03em;
}
.pw-fields-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
/* [GLOBAL utility] centers a .status-banner's content — most banners are
   left-aligned status/error text, but this page's password-form banner
   sits centered under a centered form. */
.status-banner.centered { justify-content: center; }
.admin-admin-chip:hover #adminName, .admin-admin-chip:focus #adminName { color: #0042d1;}
#addLocationBtn { font-size: 18px;  padding: 12px 20px; }
#adminListCard .card-header-row { margin-bottom: 15px;}
#adminListCard #adminList { margin-top: 30px;}










