/* public/assets/css/v365-theme.css — Vault365 portal theme (UX spec §2, §3; design §16.10).
 * Load AFTER vendor/tabler/tabler.min.css and vendor/tabler-icons/tabler-icons.min.css.
 * /theme.css (the Appearance version in use, S28) loads after this file and overrides the Appearance
 * tokens of sections 2 and 10 with their used values; reseller /brand.css (P5) after that. The values
 * here are the Vault365 defaults, used whenever /theme.css can't load.
 * Class names prefixed v365- are portal components; everything else is Tabler 1.6.1.
 *
 * Appearance and preview panes (design §16.10 item 4): every mapping block below matches :root, any
 * element with its own data-bs-theme (the dark sidebar, a menu that follows the page's theme) and
 * .v365-scope (S28's preview panes, class="v365-scope" data-bs-theme="light|dark"), so a pane
 * recomputes every Tabler colour from the --v365-* values set on it. Nothing else uses .v365-scope.
 *
 * Contents: 1 fonts · 2 Appearance tokens · 3 Tabler mappings · 4 typography · 5 sidebar · 6 top bar,
 * switcher, account menu, help drawer · 7 restricted boxes · 8 allowance and coverage · 9 strips ·
 * 10 charts · 11 info popover · 12 icons · 13 auth pages · 14 loading · 15 htmx · 16 phones ·
 * 16a contrast fixes · 16b text and markers in the primary colour · 17 components · 18 screen
 * components for the Phase 1 pages · 19 print */

/* ---------- 1. Self-hosted variable fonts (Fontsource unicode ranges) ---------- */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../vendor/fonts/inter-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../vendor/fonts/inter-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../vendor/fonts/inter-tight-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter Tight";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../vendor/fonts/inter-tight-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- 2. Appearance tokens (design §16.2): the Vault365 defaults ----------
   Picked values are the S28 settings of a fresh install; derived values (text on fills, links, brand
   ink, brand line) are what the auto-fix makes of those defaults (design §16.4), so this file and
   /theme.css without a saved version give the same page except for the light primary, which the
   auto-fix uses as #017ca5 (#0180aa with white text is 4.497:1). Lower-case #rrggbb only. */
:root {
  --v365-brand: #0180aa;          /* primary, light mode (setting; used as #017ca5) */
  --v365-brand-fg: #ffffff;       /* text on the primary (derived) */
  --v365-brand-dark: #00a9e0;     /* primary, dark mode */
  --v365-brand-dark-fg: #001f2e;  /* navy text on cyan, 6.27:1 (derived) */
  --v365-link: #017ca5;           /* links, light mode: 4.53:1 on the page (derived) */
  --v365-link-dark: #00a9e0;      /* links, dark mode (derived) */
  --v365-brand-ink: #017196;      /* text drawn in the primary colour, light mode (derived) */
  --v365-brand-ink-dark: #00a9e0; /* text drawn in the primary colour, dark mode (derived) */
  --v365-brand-line: #017ca5;     /* underlines, markers and checked boxes, light mode (derived) */
  --v365-brand-line-dark: #00a9e0;
  --v365-accent: #00a9e0;         /* logo cyan: active-menu marker and its tint, focus ring; never text, never a chart colour */
  --v365-nav-bg: #003d57;         /* sidebar on a light page (white text 11.63:1) */
  --v365-nav-bg-dark: #00141e;    /* sidebar on a dark page */
  --v365-page-bg: #f9fafb;        /* page background, light mode */
  --v365-page-bg-dark: #001f2e;   /* page background, dark mode */
  --v365-card-bg: #ffffff;        /* cards, tables, charts and menus, light mode */
  --v365-card-bg-dark: #0b2b3b;   /* the same, dark mode */
}
:root[data-bs-theme="dark"] {
  --v365-accent: #00a9e0;         /* the accent's dark-mode value (same name, design §16.2) */
}

/* Fixed tokens (never on S28, never branded) */
:root {
  --v365-font-body: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --v365-font-heading: "Inter Tight", "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --v365-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --v365-warm: #a29791;           /* decorative only: fails as text */
  --v365-petrol: #014e68;
  --v365-ink: #001f2e;            /* sign-in side panel, email header */
  --v365-slate: #455a64;          /* emphasised secondary text (7.2:1) */
  --v365-over-text: #b94a00;      /* "Over allowance" as TEXT: Tabler orange is only 3.0:1 on white */
  --v365-red-text: #b42318;       /* red status words on their light pill (section 16a) */
  --v365-topbar-height: 56px;
}
:root[data-bs-theme="dark"] {
  --v365-petrol: #cdd5da;
  --v365-over-text: #ff922b;
  --v365-red-text: #f28b82;
}

/* Preview panes (S28): a pane takes the same-name values of its own mode, whatever the page's mode.
   v365-appearance.js sets the edited Appearance values on the pane itself (style.setProperty), which
   win over these defaults; the fixed ones (petrol, status text) always come from here. */
.v365-scope {
  --v365-accent: #00a9e0;
  --v365-petrol: #014e68;
  --v365-over-text: #b94a00;
  --v365-red-text: #b42318;
}
.v365-scope[data-bs-theme="dark"] {
  --v365-accent: #00a9e0;
  --v365-petrol: #cdd5da;
  --v365-over-text: #ff922b;
  --v365-red-text: #f28b82;
}

/* ---------- 3. Map the tokens onto Tabler ----------
   On :root: Tabler computes derived colours (-darken, -lt, -200, link, focus ring) on :root, so a
   primary set on <body> or a wrapper would leave those on the old colour. Elements with their own
   data-bs-theme and the preview panes re-declare them (Tabler's :root block doesn't reach them). */
:root,
.v365-scope {
  --tblr-font-sans-serif: var(--v365-font-body);   /* --tblr-body-font-family follows it */
  --tblr-border-radius-scale: 1;                    /* cards 8 px, inputs/buttons 6 px; not brandable */

  /* Brand-tinted grey ramp (hue ~230 = the logo/navy hue). Tabler builds BOTH modes from it:
     light: page bg 50, borders 200, muted text 500, headings 900, tooltips 900
     dark:  page bg 900, cards 800, borders 700, muted text 400, body text 200 */
  --tblr-gray-50: #f9fafb;
  --tblr-gray-100: #f3f4f5;
  --tblr-gray-200: #e5e7eb;
  --tblr-gray-300: #cdd5da;
  --tblr-gray-400: #9aaab3;
  --tblr-gray-500: #5e6e78;   /* 5.3:1 on white */
  --tblr-gray-600: #455a64;
  --tblr-gray-700: #2f3f48;
  --tblr-gray-800: #0b2b3b;
  --tblr-gray-900: #001f2e;
  --tblr-gray-950: #00141e;

  /* Focus ring (§2.10): accent-tinted, 0.25rem */
  --tblr-focus-ring-width: 0.25rem;
  --tblr-focus-ring-color: color-mix(in oklab, var(--v365-accent) 40%, transparent);

  --v365-nav: var(--v365-nav-bg);
}
:root[data-bs-theme="dark"],
.v365-scope[data-bs-theme="dark"] {
  --v365-nav: var(--v365-nav-bg-dark);
}

/* Colours per mode: primary and its text, page and card backgrounds, links, body text, and the two
   colours derived for text and markers in the primary colour (section 16b). */
:root,
[data-bs-theme="light"],
.v365-scope {
  --tblr-primary: var(--v365-brand);
  --tblr-primary-fg: var(--v365-brand-fg);
  --tblr-body-bg: var(--v365-page-bg);
  --tblr-bg-surface: var(--v365-card-bg);
  --tblr-link-color: var(--v365-link);
  --tblr-body-color: light-dark(#1c1c1c, var(--tblr-gray-200));
  --v365-primary-ink: var(--v365-brand-ink);
  --v365-primary-line: var(--v365-brand-line);
}
:root[data-bs-theme="dark"],
[data-bs-theme="dark"],
.v365-scope[data-bs-theme="dark"] {
  --tblr-primary: var(--v365-brand-dark);
  --tblr-primary-fg: var(--v365-brand-dark-fg);
  --tblr-body-bg: var(--v365-page-bg-dark);
  --tblr-bg-surface: var(--v365-card-bg-dark);
  --tblr-link-color: var(--v365-link-dark);
  --v365-primary-ink: var(--v365-brand-ink-dark);
  --v365-primary-line: var(--v365-brand-line-dark);
}
/* Tabler's own derived primary colours, recomputed where the primary is re-declared (same formulas as
   tabler.min.css's :root block). */
[data-bs-theme],
.v365-scope {
  --tblr-primary-darken: oklch(from var(--tblr-primary) calc(l - 0.06) c h);
  --tblr-primary-lt: color-mix(in oklab, var(--tblr-primary) 10%, transparent);
  --tblr-primary-200: color-mix(in oklab, var(--tblr-primary) 20%, transparent);
}
.v365-scope {
  background: var(--tblr-body-bg);
  color: var(--tblr-body-color);
}

/* Page gutter: 16 px at every width, so phones keep a 16 px side gutter (§2.5).
   Same selectors as Tabler's rule (which drops to 0.5rem below lg); later in the cascade wins. */
:root,
[data-bs-theme="light"],
[data-theme="light"] {
  --tblr-page-padding: 1rem;
}

.form-control:focus,
.form-select:focus,
.btn:focus-visible {
  box-shadow: 0 0 0 var(--tblr-focus-ring-width) var(--tblr-focus-ring-color);
}

/* ---------- 4. Typography (§2.4) ---------- */
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6,
.page-title, .card-title, .modal-title, .empty-title, .navbar-brand, .offcanvas-title,
.display-1, .display-2, .display-3, .display-4, .display-5, .display-6 {
  font-family: var(--v365-font-heading);
}
.page-title { font-size: 1.25rem; line-height: 1.75rem; font-weight: 600; }
.card-title { font-size: 1rem; line-height: 1.5rem; font-weight: 600; }
.h2 { line-height: 1.4; }

/* Numbers: tabular figures everywhere they line up */
.v365-num { font-variant-numeric: tabular-nums; }
td.v365-num, th.v365-num, .table .v365-num { text-align: end; }

/* Display numbers in stat cards */
.v365-stat {
  font-family: var(--v365-font-heading);
  font-size: 1.75rem;
  line-height: 1.15;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--tblr-heading-color, inherit);
  margin: 0.25rem 0;
}

/* Answer sentence: the first line of a page (§1.1) */
.v365-answer {
  font-size: 1.125rem;
  line-height: 1.5;
  font-weight: 400;
  margin-bottom: 1rem;
  text-wrap: pretty;
}
.v365-answer strong, .v365-answer b { font-weight: 600; }
.v365-answer > .ti:first-child { margin-inline-end: 0.375rem; vertical-align: -0.125em; }

/* Small / help text, "as of" lines */
.v365-help { font-size: 0.8125rem; line-height: 1.4; color: var(--tblr-secondary); }

/* Code-like values: signup codes, recovery codes, setup key */
.v365-code { font-family: var(--v365-font-mono); font-size: 0.9375rem; font-weight: 500; letter-spacing: 0.02em; }

/* "Over allowance" as text (orange, at a readable contrast) */
.v365-over-text { color: var(--v365-over-text) !important; font-weight: 600; }

/* ---------- 5. Sidebar (§7.2): <aside class="navbar navbar-vertical navbar-expand-lg v365-navbar-brand" data-bs-theme="dark"> ----------
   Every sidebar text is a solid colour that the Appearance auto-fix checks as drawn (design §16.4
   role 2, §16.10 item 3): white in the dark variant (items, section titles, the company group, its ×,
   "Powered by"); in the light variant the body text, with the secondary text for muted lines. No 70 %
   or reduced-opacity text. */
.navbar.v365-navbar-brand {
  --tblr-navbar-bg: var(--v365-nav);
  --tblr-navbar-border-color: transparent;
  --tblr-navbar-color: #ffffff;
  --tblr-navbar-hover-color: #ffffff;
  --tblr-navbar-active-color: #ffffff;
  --tblr-navbar-active-bg: color-mix(in oklab, var(--v365-accent) 18%, transparent);
  --tblr-navbar-active-border-color: var(--v365-accent);
  --v365-nav-muted: var(--tblr-navbar-color);
  background: var(--v365-nav);
}
.navbar-vertical.v365-navbar-brand .nav-item.active > .nav-link {
  box-shadow: inset 3px 0 0 var(--tblr-navbar-active-border-color);
  color: var(--tblr-navbar-active-color);
}
.navbar-vertical.v365-navbar-brand .navbar-nav .nav-link:hover { color: var(--tblr-navbar-hover-color); }
.navbar-vertical.v365-navbar-brand .navbar-nav .nav-section-title {
  display: block;                       /* also in the phone menu */
  color: var(--tblr-navbar-color);      /* Tabler mixes it to 70 %; titles stay distinct by size, weight and capitals */
  font-size: 0.75rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.navbar-vertical.v365-navbar-brand .navbar-nav .nav-section-title.v365-nav-company {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  text-transform: none;
  letter-spacing: 0;
  font-size: 0.8125rem;
  color: var(--tblr-navbar-active-color);
}
.v365-nav-company .btn-close-group {
  margin-inline-start: auto;
  color: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5rem;
  min-height: 1.5rem;
  border-radius: var(--tblr-border-radius);
}
/* Focus in the sidebar: a solid ring in the accent, which the auto-fix keeps at 3:1 against the sidebar
   it is drawn on (design §16.4 role 5, WCAG 1.4.11); the page's 40 % accent glow is too faint on the navy.
   (The account trigger has its own inset ring below; the account menu follows the page and keeps its ring.) */
.navbar-vertical.v365-navbar-brand .navbar-nav .nav-link:focus-visible,
.navbar-vertical.v365-navbar-brand .navbar-brand a:focus-visible,
.v365-nav-company .btn-close-group:focus-visible {
  outline: 2px solid var(--v365-accent);
  outline-offset: -2px;
  box-shadow: none;
}
.navbar-vertical.v365-navbar-brand .navbar-brand { padding-top: 1.5rem; }
.navbar-vertical.v365-navbar-brand .navbar-brand-image { height: 32px; width: auto; }
.navbar-vertical.v365-navbar-brand .v365-nav-dot { width: 0.5rem; height: 0.5rem; margin-inline-start: auto; }
.navbar-vertical.v365-navbar-brand .nav-link > .badge { margin-inline-start: auto; }
.v365-navbar-brand .v365-nav-muted { color: var(--v365-nav-muted); }
.v365-navbar-brand .v365-powered { font-size: 0.75rem; color: var(--v365-nav-muted); padding: 0.25rem 1.25rem 0.75rem; }

/* Light sidebar variant (design §16.4 role 2: dark text beats white on the sidebar colour; P5: a reseller
   without a dark-background logo). Rendered WITHOUT data-bs-theme="dark" on <aside>. */
.navbar.v365-navbar-brand.v365-navbar-light {
  --tblr-navbar-border-color: var(--tblr-border-color);
  --tblr-navbar-color: var(--tblr-body-color);
  --tblr-navbar-hover-color: var(--tblr-body-color);
  --tblr-navbar-active-color: var(--tblr-body-color);
  --v365-nav-muted: var(--tblr-secondary);
  border-inline-end: 1px solid var(--tblr-border-color);
}
:root[data-bs-theme="dark"] .v365-navbar-light .navbar-brand-image {
  background: #ffffff;
  border-radius: 8px;
  padding: 8px;
  box-sizing: content-box;
}

/* Account row in the sidebar footer: the initials avatar is an outline in the sidebar's own text colour,
   so its letters are drawn straight on the sidebar (a colour the auto-fix checks). */
.v365-account { position: relative; }
.v365-account-trigger {
  width: 100%;
  text-align: start;
  color: var(--tblr-navbar-color) !important;
  border-radius: var(--tblr-border-radius);
}
.v365-account-trigger:hover { background: var(--tblr-navbar-active-bg); }
.v365-account-trigger:focus-visible { outline: 0; box-shadow: inset 0 0 0 2px var(--v365-accent); }
.v365-account-trigger .avatar {
  background: transparent;
  color: inherit;
  box-shadow: inset 0 0 0 1px currentColor;
  flex: none;
}
.v365-account-trigger > .ti { flex: none; font-size: 1rem; }

/* Phone top bar logo: 28 px (§2.7). In the phone menu Tabler hides footer link labels; "Help" keeps its word. */
@media (max-width: 991.98px) {
  .navbar-vertical.v365-navbar-brand .navbar-brand { padding-top: 0.5rem; padding-bottom: 0.5rem; }
  .navbar-vertical.v365-navbar-brand .navbar-brand-image { height: 28px; }
  .navbar-vertical.v365-navbar-brand .navbar-footer .nav-link-title { display: inline; }
}

/* ---------- 6. Top bar, company switcher (§7.3), account menu (§7.4), help drawer (§7.5) ---------- */
.v365-topbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: var(--v365-topbar-height);
  padding: 0 calc(var(--tblr-page-padding) + 0.5rem);
  border-bottom: 1px solid var(--tblr-border-color);
  background: var(--tblr-bg-surface);
}
.v365-topbar .v365-topbar-start { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.v365-topbar .v365-topbar-end { margin-inline-start: auto; display: flex; align-items: center; gap: 0.25rem; }
.v365-topbar .btn .status-dot { margin-inline-end: 0.25rem; }
.v365-topbar .v365-topbar-name { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v365-switcher-btn { max-width: 32rem; }
.v365-switcher-btn .v365-switcher-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v365-switcher-btn kbd { margin-inline-start: 0.5rem; font-size: 0.6875rem; }
.v365-switcher-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  min-height: 44px;
  padding: 0.5rem var(--tblr-page-padding);
  border: 0;
  border-bottom: 1px solid var(--tblr-border-color);
  background: var(--tblr-bg-surface);
  color: inherit;
  text-align: start;
  font-weight: 500;
}
.v365-switcher-bar:focus-visible { outline: 0; box-shadow: inset 0 0 0 var(--tblr-focus-ring-width) var(--tblr-focus-ring-color); }
.v365-fresh-popover .popover-body { white-space: pre-line; }   /* one source per line (§3.8) */
.v365-switcher-list { max-height: min(60vh, 32rem); overflow-y: auto; }
.modal-fullscreen-sm-down .v365-switcher-list { max-height: none; }
.v365-switcher-list .list-group-item.active,
.v365-switcher-list .list-group-item[aria-selected="true"] {
  background: var(--tblr-active-bg);
  color: inherit;
  border-color: var(--tblr-border-color);
  box-shadow: inset 3px 0 0 var(--v365-primary-line);
}
.v365-switcher-list .v365-switcher-group {
  font-size: 0.75rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--tblr-secondary);
  padding: 0.75rem 1rem 0.25rem;
}
.v365-switcher-list [hidden] { display: none !important; }

/* Account menu (§7.4): a floating drop-up from the sidebar footer. Tabler renders dropdowns inside
   a vertical navbar inline (position: static); this one floats above its trigger instead. It follows
   the page's theme (data-v365-follow-theme), not the sidebar's. */
.navbar-vertical .navbar-collapse .dropup > .dropdown-menu.v365-account-menu {
  position: absolute;
  inset: auto 0.5rem calc(100% + 0.25rem) 0.5rem;   /* the sidebar's width less 1rem: never wider than the sidebar (no scroll bar) */
  width: auto;
  min-width: 0;
  padding: var(--tblr-dropdown-padding-y, 0.25rem) 0;
  color: var(--tblr-body-color);
  background-color: var(--tblr-bg-surface);
  border: 1px solid var(--tblr-border-color);
  border-radius: var(--tblr-border-radius-lg, 8px);
  box-shadow: var(--tblr-shadow-dropdown, 0 16px 24px 2px rgba(0, 0, 0, 0.07));
  z-index: 1035;
}
.navbar-vertical .navbar-collapse .dropup > .dropdown-menu.v365-account-menu .dropdown-item {
  display: flex;
  align-items: center;
  width: 100%;
  padding: var(--tblr-dropdown-item-padding-y, 0.5rem) var(--tblr-dropdown-item-padding-x, 0.75rem);
  color: var(--tblr-body-color);
  border-radius: 0;
}
.navbar-vertical .navbar-collapse .dropup > .dropdown-menu.v365-account-menu .dropdown-item:hover,
.navbar-vertical .navbar-collapse .dropup > .dropdown-menu.v365-account-menu .dropdown-item:focus-visible {
  background: var(--tblr-hover-bg, var(--tblr-active-bg));
}
.v365-account-menu .dropdown-header { text-transform: none; letter-spacing: 0; font-size: 0.875rem; padding: 0.5rem 0.75rem; color: var(--tblr-body-color); }
.v365-account-menu .dropdown-item > .badge { margin-inline-start: auto; }
.v365-account-menu .v365-menu-label { font-size: 0.8125rem; color: var(--tblr-secondary); margin-bottom: 0.25rem; }
.v365-account-menu .nav-segmented .nav-link { flex: 1 1 0; justify-content: center; }
/* Phone menu: the account row sits near the top of the screen, so the menu opens downwards. */
@media (max-width: 991.98px) {
  .navbar-vertical .navbar-collapse .dropup > .dropdown-menu.v365-account-menu { inset: calc(100% + 0.25rem) auto auto 0.5rem; width: min(20rem, calc(100% - 1rem)); }
}

/* Help drawer (§7.5): offcanvas-end at 480 px. (.v365-help alone is the small help-text style of
   section 4; the drawer is .v365-help-drawer.) */
.offcanvas.v365-help,
.offcanvas.v365-help-drawer { --tblr-offcanvas-width: 480px; }
.offcanvas.v365-help { font-size: inherit; color: var(--tblr-offcanvas-color, var(--tblr-body-color)); }
.v365-help dt, .v365-help-drawer dt { font-weight: 600; }
.v365-help dd, .v365-help-drawer dd { color: var(--tblr-secondary); margin-bottom: 0.75rem; }
.v365-help-drawer .offcanvas-body > h3 { margin-top: 0; }

/* A table that scrolls sideways inside its card (§1.7) must also contain its visually hidden captions
   and labels (position: absolute), or they escape the scroll box and widen the whole page. */
.table-responsive { position: relative; }

/* Calm status (§1.6, §3.4): healthy states are a small green dot and muted text, never a filled pill */
.status.v365-calm { background: transparent; padding-inline: 0; color: var(--tblr-secondary); font-weight: 400; }
.v365-min-0 { min-width: 0; }

/* Keyboard shortcuts sheet */
.v365-shortcuts dt { font-weight: 400; }
.v365-shortcuts dd { margin-bottom: 0.5rem; }

/* ---------- 7. Restricted boxes: Partner view / Staff only (§3.10) ---------- */
.card.v365-restricted {
  border: 1px dashed var(--tblr-border-color-dark, var(--tblr-gray-400));
  background: transparent;
  box-shadow: none;
}
.card.v365-restricted > .card-header { border-bottom-style: dashed; gap: 0.5rem; }
.v365-restricted .badge .ti { margin-inline-end: 0.25rem; }
.v365-preview-banner { position: sticky; top: 0; z-index: 1020; margin: 0; border-radius: 0; }

/* ---------- 8. Allowance bar (§3.14) and coverage rows (§3.15) ---------- */
.v365-allowance { display: flex; align-items: center; gap: 0.25rem; }
.v365-allowance .progress { flex: 1 1 auto; }
.progress.v365-allowance-guides {
  /* faint guide marks at 80% and 100% of the track */
  background-image:
    linear-gradient(to right,
      transparent calc(80% - 1px), var(--tblr-border-color-dark, var(--tblr-gray-400)) calc(80% - 1px),
      var(--tblr-border-color-dark, var(--tblr-gray-400)) 80%, transparent 80%,
      transparent calc(100% - 1px), var(--tblr-border-color-dark, var(--tblr-gray-400)) calc(100% - 1px));
}
.v365-over-marker { color: var(--tblr-orange); line-height: 1; }
.progress-bar.v365-seg-long { opacity: 0.4; }
.legend.v365-legend-long .legend-dot { opacity: 0.4; }
.v365-coverage + .v365-coverage { margin-top: 0.75rem; }
.v365-coverage .legend-list { font-size: 0.8125rem; }

/* ---------- 9. Day strips and item calendar (§3.16, C8) ---------- */
.tracking-block.v365-today { outline: 1px dashed var(--tblr-gray-400); outline-offset: -1px; }
.tracking-block.v365-missed,
.tracking-block.v365-block-missed { box-shadow: inset 0 0 0 1px var(--tblr-red); }
.tracking.v365-strip { --tblr-tracking-height: 1rem; }
.tracking-squares.v365-calendar { --tblr-tracking-block-min-width: 12px; --tblr-tracking-gap-width: 3px; max-width: 100%; }
.tracking-squares.v365-calendar .tracking-block { flex: 0 0 12px; }
.v365-scroll-x { overflow-x: auto; mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent); }

/* ---------- 10. Charts (§9; UX §2.3). Hex on purpose: ApexCharts does colour maths on these ----------
   v365-app.js reads every chart colour from these custom properties (on the chart's own element)
   when a chart is built and again on a theme change; it never hard-codes a configurable colour.
   Configurable on S28: chart-1, chart-1-line, chart-baas, chart-baas-archive, chart-limit, chart-over,
   chart-2 … chart-5 (and the derived allowance label). Fixed: chart-6, chart-fore, chart-grid,
   chart-over-label. */
:root {
  --v365-chart-1: #00a9e0;             /* Microsoft 365 storage: area fill (logo cyan) */
  --v365-chart-1-line: #0180aa;        /* Microsoft 365 storage: line */
  --v365-chart-2: #014e68;             /* people protected; storage area 2 */
  --v365-chart-3: #a29791;             /* storage area 3; storage location 2 */
  --v365-chart-4: #7fd4f0;             /* storage area 4 */
  --v365-chart-5: #003d57;             /* storage area 5; storage location 3 */
  --v365-chart-6: #9aaab3;             /* storage areas 6+ (fixed) */
  --v365-chart-baas: #6741d9;          /* BaaS Storage; "Recent backups"; storage location 1 */
  --v365-chart-baas-archive: #b197fc;  /* BaaS Storage "Long-term archive" */
  --v365-chart-limit: #455a64;         /* allowance line: neutral slate, dashed — never a warning colour */
  --v365-chart-limit-label-bg: #455a64;
  --v365-chart-limit-label-fg: #ffffff;
  --v365-chart-over: #f76707;          /* "Over allowance" band (opacity set by v365-app.js: 0.06 light / 0.10 dark) */
  --v365-chart-over-label: #1c1c1c;    /* the band's label text (fixed) */
  --v365-chart-fore: #5e6e78;          /* axis text = gray-500 (fixed) */
  --v365-chart-grid: #e5e7eb;          /* = gray-200 (fixed) */
}
:root[data-bs-theme="dark"] {
  --v365-chart-1: #00a9e0;
  --v365-chart-1-line: #00a9e0;
  --v365-chart-2: #cdd5da;
  --v365-chart-3: #a29791;
  --v365-chart-4: #7fd4f0;
  --v365-chart-5: #5e6e78;
  --v365-chart-baas: #8f6cf5;
  --v365-chart-baas-archive: #5e45b8;
  --v365-chart-limit: #cdd5da;
  --v365-chart-limit-label-bg: #cdd5da;
  --v365-chart-limit-label-fg: #001f2e;
  --v365-chart-over: #f76707;
  --v365-chart-over-label: #f3f4f5;
  --v365-chart-fore: #9aaab3;
  --v365-chart-grid: #2f3f48;
}
.v365-scope {
  --v365-chart-1: #00a9e0;
  --v365-chart-1-line: #0180aa;
  --v365-chart-2: #014e68;
  --v365-chart-3: #a29791;
  --v365-chart-4: #7fd4f0;
  --v365-chart-5: #003d57;
  --v365-chart-baas: #6741d9;
  --v365-chart-baas-archive: #b197fc;
  --v365-chart-limit: #455a64;
  --v365-chart-limit-label-bg: #455a64;
  --v365-chart-limit-label-fg: #ffffff;
  --v365-chart-over: #f76707;
  --v365-chart-over-label: #1c1c1c;
  --v365-chart-fore: #5e6e78;
  --v365-chart-grid: #e5e7eb;
}
.v365-scope[data-bs-theme="dark"] {
  --v365-chart-1: #00a9e0;
  --v365-chart-1-line: #00a9e0;
  --v365-chart-2: #cdd5da;
  --v365-chart-3: #a29791;
  --v365-chart-4: #7fd4f0;
  --v365-chart-5: #5e6e78;
  --v365-chart-baas: #8f6cf5;
  --v365-chart-baas-archive: #5e45b8;
  --v365-chart-limit: #cdd5da;
  --v365-chart-limit-label-bg: #cdd5da;
  --v365-chart-limit-label-fg: #001f2e;
  --v365-chart-over: #f76707;
  --v365-chart-over-label: #f3f4f5;
  --v365-chart-fore: #9aaab3;
  --v365-chart-grid: #2f3f48;
}
:root,
.v365-scope {
  /* Same palette under Tabler's and ApexCharts' own token names (ApexCharts 7 reads --apx-* when theme.tokens is on) */
  --tblr-chart-1: var(--v365-chart-1);
  --tblr-chart-2: var(--v365-chart-2);
  --tblr-chart-3: var(--v365-chart-3);
  --tblr-chart-4: var(--v365-chart-4);
  --tblr-chart-5: var(--v365-chart-5);
  --apx-accent: var(--v365-chart-1);
  --apx-fore: var(--v365-chart-fore);
  --apx-grid: var(--v365-chart-grid);
  --apx-series-1: var(--v365-chart-1);
  --apx-series-2: var(--v365-chart-2);
  --apx-series-3: var(--v365-chart-3);
  --apx-series-4: var(--v365-chart-4);
  --apx-series-5: var(--v365-chart-5);
}
:root[data-bs-theme="dark"],
.v365-scope[data-bs-theme="dark"] {
  --tblr-chart-1: var(--v365-chart-1);
  --tblr-chart-2: var(--v365-chart-2);
  --tblr-chart-3: var(--v365-chart-3);
  --tblr-chart-4: var(--v365-chart-4);
  --tblr-chart-5: var(--v365-chart-5);
  --apx-accent: var(--v365-chart-1);
  --apx-fore: var(--v365-chart-fore);
  --apx-grid: var(--v365-chart-grid);
  --apx-series-1: var(--v365-chart-1);
  --apx-series-2: var(--v365-chart-2);
  --apx-series-3: var(--v365-chart-3);
  --apx-series-4: var(--v365-chart-4);
  --apx-series-5: var(--v365-chart-5);
}

/* Chart colours for HTML legends, swatches and the S28 "Storage areas" strip (no inline styles) */
.v365-bg-chart-1 { background-color: var(--v365-chart-1) !important; }
.v365-bg-chart-1-line { background-color: var(--v365-chart-1-line) !important; }
.v365-bg-chart-2 { background-color: var(--v365-chart-2) !important; }
.v365-bg-chart-3 { background-color: var(--v365-chart-3) !important; }
.v365-bg-chart-4 { background-color: var(--v365-chart-4) !important; }
.v365-bg-chart-5 { background-color: var(--v365-chart-5) !important; }
.v365-bg-chart-6 { background-color: var(--v365-chart-6) !important; }
.v365-bg-chart-baas { background-color: var(--v365-chart-baas) !important; }
.v365-bg-chart-baas-archive { background-color: var(--v365-chart-baas-archive) !important; }
.v365-bg-chart-limit { background-color: var(--v365-chart-limit) !important; }
.v365-bg-chart-over { background-color: var(--v365-chart-over) !important; }

/* Chart host: reserves the final height so nothing jumps (§3.13) */
.v365-chart { position: relative; min-height: 320px; }
.v365-chart[data-height="280"] { min-height: 280px; }
.v365-chart[data-height="240"] { min-height: 240px; }
.v365-chart[data-height="220"] { min-height: 220px; }
.v365-chart[data-height="200"] { min-height: 200px; }
.v365-chart[data-height="140"] { min-height: 140px; }
@media (max-width: 575.98px) {
  .v365-chart, .v365-chart[data-height] { min-height: 220px; }
  .v365-chart[data-height="200"] { min-height: 200px; }
  .v365-chart[data-height="140"] { min-height: 140px; }
}
.v365-chart > .placeholder-glow { position: absolute; inset: 0; }
.v365-chart > .placeholder-glow .placeholder { width: 100%; height: 100%; }
.v365-chart-table { max-height: 24rem; overflow: auto; }
.v365-chart-table caption { caption-side: top; color: var(--tblr-secondary); font-size: 0.8125rem; }
.v365-chart-failed { display: flex; align-items: center; justify-content: center; min-height: inherit; color: var(--tblr-secondary); font-size: 0.875rem; text-align: center; padding: 1rem; }

/* Chart tooltip (custom HTML built by v365-app.js; every string escaped there) */
.v365-tt { padding: 0.5rem 0.75rem; min-width: 12rem; max-width: min(20rem, calc(100vw - 2rem)); font-size: 0.8125rem; line-height: 1.4; }
.v365-tt-row > span { min-width: 0; overflow-wrap: anywhere; }   /* long storage-area or location names wrap: the page never scrolls sideways */
.v365-tt-head { font-weight: 600; margin-bottom: 0.375rem; }
.v365-tt-row { display: flex; align-items: baseline; gap: 0.5rem; }
.v365-tt-row + .v365-tt-row { margin-top: 0.25rem; }
.v365-tt-row > strong { margin-inline-start: auto; font-variant-numeric: tabular-nums; font-weight: 600; }
.v365-tt-note { color: var(--tblr-secondary); font-size: 0.75rem; margin-top: -0.125rem; }
.v365-tt-sum { border-top: 1px solid var(--tblr-border-color); margin-top: 0.375rem; padding-top: 0.375rem; }
.v365-tt-swatch { display: inline-block; width: 0.5rem; height: 0.5rem; border-radius: 50%; flex: none; align-self: center; }
.v365-tt-swatch[data-c="1"] { background: var(--v365-chart-1); }
.v365-tt-swatch[data-c="2"] { background: var(--v365-chart-2); }
.v365-tt-swatch[data-c="3"] { background: var(--v365-chart-3); }
.v365-tt-swatch[data-c="4"] { background: var(--v365-chart-4); }
.v365-tt-swatch[data-c="5"] { background: var(--v365-chart-5); }
.v365-tt-swatch[data-c="6"] { background: var(--v365-chart-6); }
.v365-tt-swatch[data-c="line"] { background: var(--v365-chart-1-line); }
.v365-tt-swatch[data-c="baas"] { background: var(--v365-chart-baas); }
.v365-tt-swatch[data-c="baas-archive"] { background: var(--v365-chart-baas-archive); }
.v365-tt-swatch[data-c="limit"] { background: var(--v365-chart-limit); }
.v365-tt-swatch[data-c="green"] { background: #2fb344; }
.v365-tt-swatch[data-c="yellow"] { background: #f59f00; }
.v365-tt-swatch[data-c="red"] { background: #d63939; }

/* ApexCharts chrome, adapted from Tabler's core/scss/vendor/_apexcharts.scss (that file ships in
   tabler-vendors.css, which is not vendored here). !important because ApexCharts injects its own
   stylesheet at runtime, after this one. */
.apexcharts-tooltip {
  --apx-tt-bg: var(--tblr-bg-surface) !important;
  --apx-tt-border: var(--tblr-border-color) !important;
  --apx-tt-color: var(--tblr-body-color) !important;
  --apx-tt-color-muted: var(--tblr-secondary) !important;
  font-family: inherit !important;
  background: var(--tblr-bg-surface) !important;
  border-color: var(--tblr-border-color) !important;
  color: var(--tblr-body-color) !important;
  box-shadow: var(--tblr-shadow-dropdown, 0 16px 24px 2px rgba(0, 0, 0, 0.07)) !important;
}
.apexcharts-tooltip-arrow {
  background: var(--tblr-bg-surface) !important;
  border-color: var(--tblr-border-color) !important;
}
.apexcharts-gridline,
.apexcharts-grid-borders line,
.apexcharts-xaxis-tick,
.apexcharts-yaxis line { stroke: var(--tblr-border-color) !important; }
.apexcharts-xaxis-label,
.apexcharts-yaxis-label,
.apexcharts-xaxis-title-text,
.apexcharts-yaxis-title-text { fill: var(--tblr-secondary) !important; }
.apexcharts-legend-text { color: inherit !important; }
.apexcharts-marker,
.apexcharts-data-labels rect { stroke: var(--tblr-bg-surface) !important; }
.apexcharts-toolbar { background: transparent !important; }
.apexcharts-menu {
  background: var(--tblr-bg-surface) !important;
  border-color: var(--tblr-border-color) !important;
  color: var(--tblr-body-color) !important;
}
.apexcharts-svg, .apexcharts-canvas { border-radius: inherit; }

/* ---------- 11. Info popover trigger (ⓘ, §3.9) ---------- */
/* Markup: <button type="button" class="btn btn-action btn-sm v365-info" data-bs-toggle="popover" …> */
.btn.btn-action.v365-info {
  --tblr-btn-padding-x: 0;
  --tblr-btn-padding-y: 0;
  width: 1.25rem;
  height: 1.25rem;
  min-width: 0;
  padding: 0;
  border: 0;
  margin-inline-start: 0.25rem;
  vertical-align: -0.25em;
  color: var(--tblr-secondary);
}
.btn.btn-action.v365-info:hover, .btn.btn-action.v365-info:focus-visible { color: var(--tblr-body-color); }
.btn.btn-action.v365-info .icon { margin: 0; font-size: 1rem; }

/* ---------- 12. Tabler Icons webfont inside Tabler's SVG-sized slots ---------- */
.ti.icon { line-height: 1; }
.avatar .ti { font-size: var(--tblr-avatar-icon-size, 1.25rem); line-height: 1; }
.nav-link-icon .ti { display: block; font-size: 1.25rem; line-height: 1; }
.empty-icon .ti { font-size: 3rem; line-height: 1; }
.btn .ti.icon { font-size: 1.125rem; }
.badge .ti.icon { font-size: 0.875rem; vertical-align: -0.125em; margin-inline-end: 0.125rem; }
.dropdown-item-icon.ti { font-size: 1.125rem; line-height: 1; }

/* Theme-dependent icons without a flash of the wrong one: the sun/moon toggle renders both */
:root[data-bs-theme="dark"] .v365-when-light,
:root:not([data-bs-theme="dark"]) .v365-when-dark { display: none !important; }

/* ---------- 13. Auth pages (S01–S06 shell) ---------- */
.v365-auth { min-height: 100%; }
.v365-auth-panel {
  background: var(--v365-ink);
  color: #f3f4f5;
  padding: 3rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.25rem;
}
.v365-auth-panel.v365-auth-panel-branded { background: var(--v365-nav-bg); }
:root[data-bs-theme="dark"] .v365-auth-panel { border-inline-end: 1px solid var(--tblr-border-color); }   /* the dark page is the panel's navy too */
.v365-auth-panel .v365-auth-logo { height: 56px; width: auto; align-self: flex-start; }
.v365-auth-panel .v365-tagline { font-family: var(--v365-font-heading); font-size: 1.25rem; font-weight: 500; color: #f3f4f5; margin: 0; }
.v365-auth-panel .v365-auth-line { color: #9aaab3; margin: 0; max-width: 28rem; }
.v365-auth-logo-sm { height: 48px; width: auto; }
.v365-auth-main { width: 100%; }
.v365-auth-theme { position: fixed; inset-inline-end: 1rem; bottom: 1rem; z-index: 1030; }
.v365-powered { font-size: 0.75rem; color: var(--tblr-secondary); }
@media (max-width: 991.98px) {
  .v365-auth-main { padding-bottom: 4.5rem !important; }   /* keep the fixed sun/moon button clear of the last line */
}

/* White tile: QR codes and light-only logos stay on white in both themes (§2.9) */
.v365-white-tile { background: #ffffff; border-radius: 8px; padding: 8px; display: inline-block; }
.v365-white-tile > svg { display: block; width: 200px; height: 200px; max-width: 100%; }

/* ---------- 14. Loading skeletons (§3.13) ---------- */
.v365-skeleton .placeholder { display: block; width: 100%; border-radius: var(--tblr-border-radius); }
.htmx-request[aria-busy="true"], [aria-busy="true"].v365-busy { opacity: 0.6; transition: opacity 0.2s; }

/* ---------- 15. htmx indicator (with htmx.config.includeIndicatorStyles = false) ---------- */
.htmx-indicator { opacity: 0; visibility: hidden; transition: opacity 200ms ease-in; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { opacity: 1; visibility: visible; }

/* ---------- 16. Phones: tap targets and stacked tables (§2.5, §7.6) ---------- */
@media (max-width: 575.98px) {
  .page-header .btn-list > .btn,
  .table-mobile-md .btn,
  .btn.v365-tap { min-height: 44px; }
  .v365-answer { font-size: 1.0625rem; }
}
/* Stacked rows read top to bottom: numbers sit under their labels like every other value. */
@media (max-width: 767.98px) {
  .table-mobile-md > tbody > tr > td.text-end { text-align: start !important; }
}

/* ---------- 16a. Contrast fixes for Tabler parts (WCAG 2.2 AA for all text, §2.10) ---------- */
/* Red status words on their light pill (Tabler: 4.0:1 light, 3.2:1 dark). The fill stays Tabler red;
   only the text is darker (light) or lighter (dark), like --v365-over-text for orange. */
.badge.bg-red-lt,
.badge.badge-outline.text-red { color: var(--v365-red-text) !important; }
/* Links take --v365-link / --v365-link-dark (section 3), worked out from the used primary and checked
   against the page and card backgrounds on the server (design §16.4 role 4). Tabler draws .btn-link
   5% lighter than links; text buttons use the link colour. */
.btn-link { color: var(--tblr-link-color); }
/* Text on primary fills follows the primary's own text colour (navy on cyan in dark mode, 6.3:1). */
.pagination { --tblr-pagination-active-color: var(--tblr-primary-fg); }
.ribbon:not([class*="bg-"]) { color: var(--tblr-primary-fg); }
.steps-counter .step-item::before { color: var(--tblr-primary-fg); }
.steps-counter .step-item.active ~ .step-item::before { color: var(--tblr-disabled-color); }
/* Muted text that Tabler takes from gray-500 (#5e6e78: 3.2:1 on dark surfaces) uses the secondary token. */
.input-group-text,
.nav-tabs .nav-link:not(.active) { color: var(--tblr-secondary); }
.nav-tabs .nav-link:not(.active):hover { color: var(--tblr-body-color); }

/* ---------- 16b. Text and markers in the primary colour (design §16.4 roles 4a–4b, §16.10 item 2) ----------
   Text drawn in the primary colour uses the brand ink (4.5:1 on the page, the card and the primary's own
   light tint); a state shown in the primary colour (selected-tab underline, the switcher's current row,
   checked boxes, the "Within allowance" bar) uses the brand line (3:1). Fills keep the primary with its
   own text colour. A new use of the primary as text or as a lone marker picks one of the two.
   Tabler parts the Phase 1 pages use that also draw the primary as text or as a marker take the same
   two: the checked choice of a form-selectgroup (account appearance, admin access fields, filter pills:
   its words and title in the ink, its border and check in the line), the active dropdown item, a
   selected stat card (card-active) and an indeterminate checkbox. */
.text-primary { color: var(--v365-primary-ink) !important; }
.bg-primary-lt,
.badge.bg-primary-lt { color: var(--v365-primary-ink) !important; }
.btn.btn-outline-primary {
  --tblr-btn-color: var(--v365-primary-ink);
  --tblr-btn-border-color: var(--v365-primary-ink);
  --tblr-btn-disabled-color: var(--v365-primary-ink);
  --tblr-btn-disabled-border-color: var(--v365-primary-ink);
}
.form-check-input:checked,
.form-check-input[type="checkbox"]:indeterminate {
  background-color: var(--v365-primary-line);
  border-color: var(--v365-primary-line);
}
/* Any progress bar in the primary colour is a state marker: the "Within allowance" bar (UX §3.14, in
   .v365-allowance, .v365-allowance-guides or with .v365-within) and S28's preview of it. */
.v365-allowance .progress-bar.bg-primary,
.progress.v365-allowance-guides > .progress-bar.bg-primary,
.progress-bar.bg-primary.v365-within,
.progress > .progress-bar.bg-primary { background-color: var(--v365-primary-line) !important; }
.form-selectgroup-input:checked + .form-selectgroup-label,
.form-selectgroup-input:focus + .form-selectgroup-label {
  color: var(--v365-primary-ink);
  border-color: var(--v365-primary-line);
}
.form-selectgroup-boxes .form-selectgroup-input:checked + .form-selectgroup-label { color: inherit; }   /* Tabler's: boxes keep their text colour */
.form-selectgroup-boxes .form-selectgroup-input:checked + .form-selectgroup-label .form-selectgroup-title { color: var(--v365-primary-ink); }
.form-selectgroup-input:checked + .form-selectgroup-label .form-selectgroup-check { background-color: var(--v365-primary-line); }
.dropdown-menu { --tblr-dropdown-link-active-color: var(--v365-primary-ink); }
.card-active { --tblr-card-border-color: var(--v365-primary-line); }

/* ---------- 17. Components added while the screens were mocked (Phase 1) ---------- */

/* Underlined page tabs under the page title (S09/S11 "Status | History"): nav.nav.v365-tabs */
.nav.v365-tabs {
  gap: 1.25rem;
  margin-top: 0.75rem;
  border-bottom: 1px solid var(--tblr-border-color);
}
.nav.v365-tabs .nav-link {
  padding: 0.5rem 0;
  margin-bottom: -1px;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--tblr-secondary);
  font-weight: 500;
}
.nav.v365-tabs .nav-link:hover { color: var(--tblr-body-color); border-bottom-color: var(--tblr-border-color); }
.nav.v365-tabs .nav-link.active {
  color: var(--tblr-body-color);
  font-weight: 600;
  background: transparent;
  border-bottom-color: var(--v365-primary-line);
}

/* Collapsible card: <details class="card v365-collapse"><summary class="card-header">…
   <i class="ti ti-chevron-down icon ms-auto v365-chevron"></i></summary>. The chevron also turns on
   any toggle button with aria-expanded="true". */
details.v365-collapse > summary { display: flex; align-items: center; gap: 0.5rem; list-style: none; cursor: pointer; }
details.v365-collapse > summary::-webkit-details-marker { display: none; }
details.v365-collapse:not([open]) > summary.card-header { border-bottom: 0; }
details.v365-collapse > summary:focus-visible { outline: 0; box-shadow: inset 0 0 0 var(--tblr-focus-ring-width) var(--tblr-focus-ring-color); }
.v365-chevron { transition: transform 0.15s ease-in-out; }
details.v365-collapse[open] > summary .v365-chevron,
[aria-expanded="true"] > .v365-chevron { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .v365-chevron { transition: none; } }

/* Detail drawer (§3.19): offcanvas-end, 480 px, for item and user detail on desktop */
.offcanvas.v365-drawer { --tblr-offcanvas-width: 480px; }

/* Sticky side panel (review panels, live previews) from lg; scrolls inside itself when taller than
   the window, so its last part stays reachable. Its column must stretch (no align-items-start). */
@media (min-width: 992px) {
  .v365-sticky {
    position: sticky;
    top: 1rem;
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    border-radius: var(--tblr-border-radius-lg, 8px);
  }
}

/* Small copy button after a value (address, reference): same shape as the ⓘ trigger */
.btn.btn-action.v365-copy {
  --tblr-btn-padding-x: 0;
  --tblr-btn-padding-y: 0;
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  min-width: 0;
  padding: 0;
  border: 0;
  color: var(--tblr-secondary);
}
.btn.btn-action.v365-copy:hover,
.btn.btn-action.v365-copy:focus-visible { color: var(--tblr-body-color); }
.btn.btn-action.v365-copy .icon { margin: 0; font-size: 1rem; }
@media (max-width: 575.98px) { .btn.btn-action.v365-copy { width: 2.75rem; height: 2.75rem; } }

/* Item calendar legend (C8): swatches matching the tracking squares. Also S28's colour swatches, drawn as
   <svg class="v365-swatch" viewBox="0 0 1 1"><rect width="1" height="1" fill="#rrggbb"/></svg> (no
   inline style; design §16.6); the outline keeps a white swatch visible on a white card. */
.v365-cal-legend { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; font-size: 0.8125rem; color: var(--tblr-secondary); }
.v365-swatch {
  display: inline-block;
  width: 12px;
  height: 12px;
  margin-inline-end: 0.375rem;
  vertical-align: -2px;
  border-radius: var(--tblr-border-radius-sm);
}
svg.v365-swatch {
  overflow: hidden;
  outline: 1px solid color-mix(in oklab, var(--tblr-body-color) 25%, transparent);
  outline-offset: -1px;
  flex: none;
}
svg.v365-swatch.v365-swatch-lg { width: 1.25rem; height: 1.25rem; vertical-align: -0.3125rem; }
.v365-swatch-strip { display: inline-flex; gap: 2px; vertical-align: middle; }
.v365-swatch-strip > .v365-swatch { margin: 0; }
.v365-swatch-missed { box-shadow: inset 0 0 0 1px var(--tblr-red); }

/* Message in a chart's place ("only just started measuring", "no readings in this range"), at the
   chart's final height so the card doesn't jump when the chart appears (§3.13) */
.v365-chart-empty { min-height: 320px; display: flex; align-items: center; justify-content: center; }
.v365-chart-empty .empty { padding: 1.5rem 1rem; }
@media (max-width: 575.98px) { .v365-chart-empty { min-height: 220px; } }

/* Stacked tables (table-mobile-md) as two-column label/value grids on phones: numbers left-aligned
   under their labels, the first cell as the row's heading. */
@media (max-width: 767.98px) {
  .v365-stack-grid.table-mobile-md tr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 0.5rem; }
  .v365-stack-grid.table-mobile-md td { text-align: start !important; padding: 0.375rem 0.75rem !important; }
  .v365-stack-grid.table-mobile-md td:first-child { grid-column: 1 / -1; padding-top: 0.75rem !important; font-weight: 600; }
  .v365-stack-grid.table-mobile-md td:first-child::before { display: none; }
  .v365-stack-grid.table-mobile-md tr > td:last-child { padding-bottom: 0.75rem !important; }
}

/* Row actions ("⋯" menu, §3.6). In stacked phone rows it becomes a full-width "Actions" button at
   least 44 px tall (§2.5): <td class="v365-rowmenu-cell"><div class="dropdown v365-rowmenu">
   <button class="btn btn-icon btn-sm">…<span class="v365-rowmenu-label">Actions</span></button> */
.v365-rowmenu-label { display: none; }
@media (max-width: 767.98px) {
  .table-mobile-md td.v365-rowmenu-cell { text-align: start; }
  .table-mobile-md td.v365-rowmenu-cell::before { display: none !important; }
  .table-mobile-md .v365-rowmenu > .btn,
  .table-mobile-md td.v365-rowmenu-cell > .btn { width: 100%; min-height: 2.75rem; display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; }
  .table-mobile-md .v365-rowmenu > .btn { border: var(--tblr-border-width) solid var(--tblr-border-color); }
  .table-mobile-md .v365-rowmenu > .btn .icon { margin: 0; }          /* btn-icon pulls its glyph in with negative margins */
  .table-mobile-md .v365-rowmenu-label { display: inline; }
  .table-mobile-md .btn-icon.btn-sm { min-width: 2.75rem; min-height: 2.75rem; }
}

/* Password field with a show/hide button: <div class="input-icon"><input class="form-control v365-pw">
   <span class="input-icon-addon"><button class="btn btn-action v365-pw-toggle"> (Tabler addons
   ignore pointer events). The button fills the addon, so the whole end of the field is the target. */
.v365-pw-toggle {
  pointer-events: auto;
  color: var(--tblr-secondary);
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  align-self: stretch;
  width: var(--tblr-input-icon-addon-width, 2.5rem);
  min-height: 100%;
  text-decoration: none;
}
.v365-pw-toggle:hover, .v365-pw-toggle:focus-visible { color: var(--tblr-body-color); }
.v365-pw-toggle:focus-visible { outline: 0; box-shadow: 0 0 0 var(--tblr-focus-ring-width) var(--tblr-focus-ring-color); border-radius: var(--tblr-border-radius); }
.v365-pw-toggle .ti.icon { font-size: 1.125rem; margin: 0; }
/* With an error, Tabler's red × (positioned with !important) moves left of the toggle. */
.input-icon .form-control.v365-pw.is-invalid {
  padding-inline-end: 5rem !important;
  background-position: right 2.875rem center !important;
  background-size: 1.25rem 1.25rem;
}

/* Six-digit code (§3.19 OTP): centred; six boxes fit a 343 px phone card */
.v365-otp { display: flex; justify-content: center; }
@media (max-width: 399.98px) {
  .v365-otp .otp-lg { --tblr-otp-size: 2.5rem; --tblr-otp-gap: 0.375rem; --tblr-otp-font-size: 1rem; }
}

/* Recovery codes: two-column monospace grid (S04, S24) */
.v365-codes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem 1rem;
  list-style: none;
  margin: 0 0 1rem;
  padding: 1rem;
  border: 1px solid var(--tblr-border-color);
  border-radius: var(--tblr-border-radius);
  background: var(--tblr-bg-surface-secondary);
}
.v365-codes li { font-family: var(--v365-font-mono); font-size: 0.9375rem; font-weight: 500; letter-spacing: 0.02em; text-align: center; }

/* Toasts (§3.17): a status stripe per level; the words carry the meaning */
.toast { border-inline-start-width: 3px; }
.toast.toast-success { border-inline-start-color: var(--tblr-success); }
.toast.toast-info { border-inline-start-color: var(--tblr-azure); }
.toast.toast-warning { border-inline-start-color: var(--tblr-warning); }
.toast.toast-danger { border-inline-start-color: var(--tblr-danger); }
.toast .toast-body { overflow-wrap: anywhere; }

/* ---------- 18. Screen components for the Phase 1 pages ----------
   Product versions of the mockup's "product candidates", so feature templates need no CSS of their own. */

/* Steps (§3.19, UX S03 phone rule): below 400 px only the numbers show, with the current step's label
   under its number. */
@media (max-width: 399.98px) {
  .steps-counter .step-item { font-size: 0; }
  .steps-counter .step-item::before { font-size: 0.8125rem; }
  .steps-counter .step-item.active { font-size: 0.875rem; white-space: nowrap; }
}

/* S25 (and S05) sample email (UX §10 template). Emails are light in every theme, like a mail client, so
   the colours are fixed: <div class="v365-email"><div class="v365-email-meta">…<div class="v365-email-card">
   <div class="v365-email-head"><img></div><div class="v365-email-body">…<p class="v365-email-cta"><a>…
   </a></p></div><div class="v365-email-foot">… */
.v365-email {
  background: #f3f4f5;
  border: 1px solid var(--tblr-border-color);
  border-radius: 8px;
  padding: 1rem;
  color: #1c1c1c;
  font-family: Inter, "Segoe UI", Arial, sans-serif;
}
.v365-email-meta { font-size: 0.75rem; color: #5e6e78; margin: 0 auto 0.75rem; max-width: 600px; display: grid; gap: 0.125rem; overflow-wrap: anywhere; }
.v365-email-meta strong { color: #1c1c1c; }
.v365-email-card { max-width: 600px; margin: 0 auto; background: #ffffff; border-radius: 8px; overflow: hidden; }
.v365-email-head { padding: 1rem 1.5rem; background: #ffffff; border-bottom: 1px solid #e5e7eb; }
.v365-email-head img { display: block; height: 40px; width: auto; }
.v365-email-body { padding: 1.25rem 1.5rem; font-size: 15px; line-height: 1.5; }
.v365-email-body h2, .v365-email-body h3 { font-family: "Inter Tight", Arial, sans-serif; font-size: 20px; font-weight: 600; color: #001f2e; margin: 0 0 0.75rem; }
.v365-email-body h4 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.04em; color: #455a64; margin: 1.25rem 0 0.375rem; }
.v365-email-body p { margin: 0 0 0.5rem; }
.v365-email-body ul { margin: 0 0 0.5rem; padding-inline-start: 1.25rem; }
.v365-email-small { font-size: 12px; color: #5e6e78; }
.v365-email-chart { display: block; margin: 0.5rem 0; max-width: 100%; height: auto; }
.v365-email-cta { margin-top: 1.25rem !important; }
.v365-email-cta a,
.v365-email-cta span {
  display: inline-block;
  background: var(--v365-brand);
  color: var(--v365-brand-fg);
  text-decoration: none;
  padding: 10px 18px;
  border-radius: 6px;
  font-weight: 600;
}
.v365-email-foot { padding: 1rem 1.5rem; border-top: 1px solid #e5e7eb; font-size: 12px; color: #5e6e78; display: grid; gap: 0.25rem; }
@media (max-width: 575.98px) {
  .v365-email { padding: 0.5rem; }
  .v365-email-body, .v365-email-head, .v365-email-foot { padding-inline: 1rem; }
}

/* S28 preview panes (U12: partials/appearance/pane.php; S22 in P5): .v365-scope.v365-preview-pane with its
   own data-bs-theme and the edited --v365-* values set on it by v365-appearance.js. Inside, a mini sidebar
   that reuses the real sidebar's classes (.navbar.navbar-vertical.v365-navbar-brand.v365-preview-nav, the
   light variant with .v365-navbar-light), so it is drawn by exactly the rules of section 5, and the page
   (.v365-preview-page) on the pane's page background. The pane is inert: a picture, not part of the form. */
.v365-preview-pane { font-size: 0.8125rem; }
.navbar.v365-preview-nav {
  position: static;
  width: 7.5rem;
  min-height: 0;
  padding: 0.5rem 0.25rem;
  box-shadow: none;
}
.navbar.v365-preview-nav .navbar-brand-image { height: 20px; width: auto; }
.navbar.v365-preview-nav .navbar-nav { flex-direction: column; gap: 2px; }
.navbar.v365-preview-nav .nav-link { color: var(--tblr-navbar-color); border-radius: 4px; min-height: 0; justify-content: start; }
.navbar.v365-preview-nav .nav-item.active > .nav-link { background: var(--tblr-navbar-active-bg); font-weight: 500; }
.v365-scope[data-bs-theme="dark"] .v365-navbar-light .navbar-brand-image { background: #ffffff; border-radius: 6px; padding: 4px; box-sizing: content-box; }
.v365-scope[data-bs-theme="light"] .v365-navbar-light .navbar-brand-image { background: transparent; padding: 0; }
.v365-preview-page { background: var(--tblr-body-bg); }
.v365-preview-chart { min-height: 140px; } /* UX S28: the compact sample C1 is 140 px */

/* ---------- 19. Print (§2.10): A4 portrait, no chrome ---------- */
@media print {
  .v365-topbar, .v365-switcher-bar, .navbar-vertical, .v365-preview-banner, .toast-container,
  .v365-auth-panel, .v365-auth-theme { display: none !important; }
  .page-wrapper { margin: 0 !important; }
  .card { break-inside: avoid; }
  .v365-restricted { border-style: dashed !important; }
  .v365-codes { background: transparent; }
}
