@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@600;700&family=IBM+Plex+Sans:wght@400;500&display=swap');

/* ==========================================================================
   Umtongata Energy ERP — design tokens (from LOOK_AND_FEEL.md)
   One global sheet, pulled in via app.js → importmap('app'). Never hardcode
   colours in templates — reference these tokens / the component classes below.
   ========================================================================== */
:root {
  /* Dark brand surfaces (persist across light & dark mode) */
  --navy-deep: #07131F;
  --navy:      #0A1A2F;
  --navy-soft: #112740;

  /* Brand */
  --brand:       #1C8FBF;
  --brand-hover: #167AA4;
  --brand-tint:  #E4F1F8;
  --accent:      #2BA4DB;

  /* Neutrals (canvas/cards invert in dark mode) */
  --bg:    #F4F7FA;
  --card:  #FFFFFF;
  --line:  #E7ECF2;
  --ink:   #102540;
  --text:  #2B3A4C;
  --muted: #6B7A8D;
  --faint: #9AA7B6;

  /* Status — always paired with an icon/label, never colour alone */
  --success: #1FA06B; --success-tint: #E5F5EE; --success-ink: #157A52;
  --warning: #E2A02E; --warning-tint: #FBF0DA; --warning-ink: #9A6B12;
  --danger:  #DF534B; --danger-tint:  #FBE6E4; --danger-ink:  #A8322C;
  --info:    var(--brand); --info-tint: var(--brand-tint); --info-ink: #146284;

  /* Shape & elevation */
  --radius-card: 12px;
  --radius-control: 8px;
  --radius-pill: 999px;
  --shadow-card: 0 1px 2px rgba(16,37,64,.04), 0 2px 8px rgba(16,37,64,.06);

  /* Type */
  --font-display: 'Plus Jakarta Sans', system-ui, sans-serif;
  --font-body:    'IBM Plex Sans', system-ui, sans-serif;

  /* Data-viz palette (LOOK_AND_FEEL): sequential blues anchored by navy + neutral grey.
     Read by the Highcharts theme in chart_controller.js. The blues persist across light/dark
     (brand surfaces), the grey track inverts in dark. */
  --viz-navy:  var(--navy);
  --viz-brand: var(--brand);
  --viz-light: #7FC4E0;
  --viz-pale:  #BFE0EF;
  --viz-grey:  #D5DDE6;

  /* BFP-trend series (Daily Movements). Two measures share ONE c/l axis, so they need to read
     apart: the BFP line, and the over/(under)-recovery as a diverging pair around zero.
     Validated with the dataviz six-checks against the LIGHT surface (#FFFFFF) — all PASS
     (worst adjacent CVD ΔE 10.7 protan / 14.2 tritan). Deliberately NOT the success/danger
     green+red, which FAILS at ΔE 5.7 under deuteranopia. Dark has its own steps below. */
  --viz-bfp:       #6b4fbb;
  --viz-recov-pos: #0d9488;
  --viz-recov-neg: #eb6834;

  /* Recovery attribution (oil vs rand). Two CATEGORICAL hues — they name a cause, not a sign, so
     they must not reuse the pos/neg pair above. Validated light (#FFFFFF): all PASS, worst
     adjacent CVD ΔE 27.2 protan. */
  --viz-attr-oil: #b45309;
  --viz-attr-fx:  #2a78d6;

  /* Shell metrics */
  --sidebar-w: 260px;
  --rail-w: 76px;
  --topbar-h: 64px;
}

/* Dark mode — canvas & cards invert; navy brand surfaces stay navy. */
[data-theme="dark"] {
  --bg:    #0A1420;
  --card:  #0F2236;
  --line:  rgba(255,255,255,.09);
  --ink:   #EAF1F8;
  --text:  #C5D2DF;
  --muted: #8B9AAC;
  --faint: #647688;

  --brand-tint:   rgba(28,143,191,.18);
  --success-tint: rgba(31,160,107,.20);  --success-ink: #5FD3A2;
  --warning-tint: rgba(226,160,46,.20);   --warning-ink: #ECC079;
  --danger-tint:  rgba(223,83,75,.20);    --danger-ink:  #F0A19B;
  --info-tint: var(--brand-tint);         --info-ink: #6FC2E6;

  /* Data-viz: blues persist; the neutral grey reads as a faint light on dark cards. */
  --viz-grey: rgba(255,255,255,.16);

  /* BFP-trend series, re-stepped for the dark surface (#0F2236) — NOT an automatic flip of the
     light values, which fall outside the dark lightness band (L 0.48–0.67). Re-validated at this
     surface: all six checks PASS (worst adjacent CVD ΔE 13.9 deutan / 11.2 tritan). */
  --viz-bfp:       #8b6ee8;
  --viz-recov-pos: #12a595;
  --viz-recov-neg: #e2662f;

  /* Attribution, re-stepped for the dark surface (#0F2236) — validated: all PASS, ΔE 26.6 protan. */
  --viz-attr-oil: #cf7a2b;
  --viz-attr-fx:  #4f93ee;

  --shadow-card: 0 1px 2px rgba(0,0,0,.30), 0 2px 10px rgba(0,0,0,.40);
}

/* ===== Base ============================================================== */
*, *::before, *::after { box-sizing: border-box; }

html { color-scheme: light; }
html[data-theme="dark"] { color-scheme: dark; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 { font-family: var(--font-display); color: var(--ink); font-weight: 700; line-height: 1.25; margin: 0; }
h1 { font-size: 28px; } h2 { font-size: 22px; } h3 { font-size: 18px; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

::selection { background: var(--brand); color: #fff; }
:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 4px; }

.num { font-variant-numeric: tabular-nums; }
.muted { color: var(--muted); }

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

/* ===== Reusable components ============================================== */

/* Buttons — Bootstrap owns .btn / .btn-* (brand colours come from the --bs-primary
   bridge). This only restores the icon+label inline layout the templates rely on: an
   <svg class="ico"> sits beside the button text with a small gap. */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: .5rem; }
.btn > .ico { width: 18px; height: 18px; }

/* Inputs & fields */
.input {
  width: 100%; min-height: 44px; padding: 10px 12px;
  background: var(--card); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius-control);
  font-family: var(--font-body); font-size: 14px;
}
.input::placeholder { color: var(--faint); }
.input:focus { outline: 2px solid var(--brand); outline-offset: 1px; border-color: var(--brand); }
.field { display: block; }
.field > .label { display: block; font-size: 13px; color: var(--muted); margin-bottom: 6px; }
.field--icon { position: relative; }
.field--icon > .input { padding-left: 42px; }
.field--icon > .field-lead { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); width: 18px; height: 18px; color: var(--faint); pointer-events: none; }
.field--icon > .field-trail { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); display: inline-flex; padding: 6px; border: none; background: none; color: var(--muted); cursor: pointer; border-radius: 6px; }
.field--icon > .field-trail:hover { color: var(--brand); }

/* Cards */
/* display:block neutralises Bootstrap's `.card { display:flex; flex-direction:column }`,
   which would otherwise re-stack flex layouts like `.card.kpi`. */
.card { display: block; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-card); box-shadow: var(--shadow-card); padding: 18px; }

/* Icon badge — circular tinted disc fronting metrics/rows */
.icon-badge { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: var(--radius-pill); background: var(--brand-tint); color: var(--brand); flex: 0 0 auto; }
.icon-badge svg, .icon-badge .ico { width: 20px; height: 20px; }

/* Status pills (tint + ink; colour AND label) */
.pill { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: var(--radius-pill); font-size: 12px; font-weight: 500; text-transform: capitalize; }
.pill--success { background: var(--success-tint); color: var(--success-ink); }
.pill--warning { background: var(--warning-tint); color: var(--warning-ink); }
.pill--danger  { background: var(--danger-tint);  color: var(--danger-ink); }
.pill--info    { background: var(--info-tint);    color: var(--info-ink); }
.pill--muted   { background: var(--line);         color: var(--muted); }

/* Flash messages */
.flash { padding: 10px 14px; border-radius: var(--radius-control); margin-bottom: 12px; font-size: 14px; }
.flash--success { background: var(--success-tint); color: var(--success-ink); }
.flash--error   { background: var(--danger-tint);  color: var(--danger-ink); }

/* Data tables */
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table thead th { text-align: left; font-size: 12px; font-weight: 500; color: var(--muted); padding: 8px 12px; border-bottom: 1px solid var(--line); }
.table tbody td { padding: 14px 12px; border-bottom: 1px solid var(--line); color: var(--text); }
.table tbody tr:hover { background: color-mix(in srgb, var(--brand) 4%, transparent); }
.table .amount { text-align: right; font-variant-numeric: tabular-nums; }
/* Wide tables never blow out their card or force the whole page to scroll sideways — they
   scroll horizontally *inside* the card instead, at EVERY width (the scrollbar only appears
   when the table is genuinely too wide). This is the main fix for tablet-width overflow, where
   a many-column table used to spill past its card and shove the sticky top bar / sidebar out
   of alignment. Covers plain tables (.card > .table) and DataTables, which (v2) wraps the
   table in .dt-container. */
.card > .table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* …with the side effect that a table NARROWER than its card shrink-wraps to its content, leaving
   dead space to the right (display:block makes the inner table an anonymous shrink-to-fit box, so
   width:100% on the <table> can't stretch it). `.table--fill` opts a table back into real table
   layout so it spans the card. Only for tables known to fit; below the tablet breakpoint it falls
   back to the scrolling block above, so the overflow protection is kept where it actually matters. */
.card > .table--fill { display: table; width: 100%; overflow: visible; }
@media (max-width: 768px) {
  .card > .table--fill { display: block; overflow-x: auto; }
}
.dt-container { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* DataTables (bs5) lays its control rows out with Bootstrap .row, whose negative gutter makes
   them ~10px wider than the card. Now that .dt-container can scroll, that would show a spurious
   horizontal scrollbar even when the table fits — zero the gutter so only a genuinely wide
   TABLE triggers the scroll. (Same .row-negative-gutter leak neutralised on the sales totals.) */
.dt-container .row { --bs-gutter-x: 0; }

/* Inline SVG icon helper (stroke icons inherit currentColor) */
.ico { width: 18px; height: 18px; display: inline-block; vertical-align: middle; }
svg.ico { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* ==========================================================================
   App shell — navy sidebar + white top bar + light canvas + right rail
   ========================================================================== */
.shell { display: grid; grid-template-columns: var(--sidebar-w) minmax(0, 1fr); min-height: 100vh; }
.shell.is-collapsed { grid-template-columns: var(--rail-w) minmax(0, 1fr); }

/* Sidebar */
.sidebar { position: sticky; top: 0; height: 100vh; background: var(--navy); color: #AEBCCB; display: flex; flex-direction: column; overflow: hidden; }
.sidebar__brand { display: flex; align-items: center; height: var(--topbar-h); padding: 0 18px; color: #fff; flex: 0 0 auto; }
/* The lockup is 1460x374 (~3.9:1), so height drives width: 44px tall renders 172px wide, which
   leaves 70px clear inside the 260px rail and 10px above/below inside the 64px brand bar.
   The collapsed mark is square and sits in the 76px rail. */
.sidebar__brand .logo { height: 44px; }
.sidebar__brand .mark { width: 44px; height: 44px; }
.sidebar__brand .logo svg, .sidebar__brand .mark svg { width: 100%; height: 100%; display: block; }
.shell:not(.is-collapsed) .sidebar__brand .mark { display: none; }
.shell.is-collapsed .sidebar__brand { justify-content: center; padding: 0; }
.shell.is-collapsed .sidebar__brand .logo { display: none; }

/* Scrollable but with the scrollbar hidden (per design). */
.sidebar__nav { flex: 1 1 auto; overflow-y: auto; padding: 8px; scrollbar-width: none; -ms-overflow-style: none; }
.sidebar__nav::-webkit-scrollbar { width: 0; height: 0; display: none; }

.nav-primary { margin-bottom: 6px; }

/* Collapsible sections (details/summary heading toggles the whole group). */
.nav-section { margin-top: 10px; }
.nav-section > summary { list-style: none; cursor: pointer; }
.nav-section > summary::-webkit-details-marker { display: none; }
.nav-section > summary::marker { content: ""; }
.nav-section__head { display: flex; align-items: center; gap: 8px; padding: 6px 12px; border-radius: var(--radius-control); transition: background .15s ease; }
.nav-section__head:hover { background: var(--navy-soft); }
.nav-section__label { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: #647C95; white-space: nowrap; flex: 1 1 auto; }
.nav-section__chev { width: 14px; height: 14px; opacity: .5; flex: 0 0 auto; color: #647C95; transition: transform .15s ease; }
.nav-section[open] > summary .nav-section__chev { transform: rotate(90deg); }
.nav-section__body { padding-top: 2px; }
.shell.is-collapsed .nav-section__head { display: none; }
.shell.is-collapsed .nav-section__body { display: block; }
.shell.is-collapsed .nav-section { margin-top: 6px; }

.nav-item { display: flex; align-items: center; gap: 12px; height: 42px; padding: 0 12px; margin: 2px 0; border-radius: var(--radius-control); color: #AEBCCB; text-decoration: none; transition: background .15s ease, color .15s ease; }
.nav-item:hover { background: var(--navy-soft); color: #fff; text-decoration: none; }
.nav-item.is-active { background: var(--brand); color: #fff; }
.nav-item__icon { width: 20px; height: 20px; flex: 0 0 auto; }
.nav-item__label { flex: 1 1 auto; white-space: nowrap; font-size: 14px; }
.nav-item__chev { width: 16px; height: 16px; opacity: .55; flex: 0 0 auto; }
.shell.is-collapsed .nav-item { justify-content: center; padding: 0; }
.shell.is-collapsed .nav-item__label, .shell.is-collapsed .nav-item__chev { display: none; }

.sidebar__rig { flex: 0 0 auto; padding: 8px 16px 16px; color: #25405E; }
.sidebar__rig svg { width: 100%; height: auto; display: block; }
.shell.is-collapsed .sidebar__rig { display: none; }

/* Collapsible nav groups (details/summary) */
.nav-group > summary { list-style: none; cursor: pointer; }
.nav-group > summary::-webkit-details-marker { display: none; }
.nav-group > summary::marker { content: ""; }
.nav-group > summary .nav-item__chev { margin-left: auto; transition: transform .15s ease; }
.nav-group[open] > summary .nav-item__chev { transform: rotate(90deg); }
.nav-group.is-current > summary { color: #fff; }
.nav-group__items { display: flex; flex-direction: column; gap: 1px; padding: 2px 0 6px; }
.nav-group__title { display: none; }

.nav-subitem { display: flex; align-items: center; gap: 11px; height: 36px; padding: 0 12px 0 36px; border-radius: var(--radius-control); color: #93A4B7; text-decoration: none; font-size: 13px; transition: background .15s ease, color .15s ease; }
.nav-subitem__icon { width: 17px; height: 17px; flex: 0 0 auto; opacity: .85; transition: color .15s ease, opacity .15s ease; }
.nav-badge { margin-left: auto; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px; background: var(--danger); color: #fff; font-size: 10px; font-weight: 700; line-height: 18px; text-align: center; flex: 0 0 auto; }
/* Locked (no-access) nav items: padlock at the end, muted, non-navigating (a toast fires on click). */
.nav-lock { margin-left: auto; width: 13px; height: 13px; flex: 0 0 auto; opacity: .7; }
.nav-item.is-locked, .nav-subitem.is-locked { cursor: not-allowed; }
.nav-item.is-locked .nav-item__label, .nav-subitem.is-locked .nav-subitem__label { opacity: .5; }
.nav-item.is-locked .nav-item__icon, .nav-subitem.is-locked .nav-subitem__icon { opacity: .4; }
.nav-item.is-locked:hover, .nav-subitem.is-locked:hover { background: rgba(255,255,255,.04); color: inherit; }
.nav-group__head.is-locked .nav-item__label { opacity: .5; }
/* View-only: the user CAN open it (read-only), so it stays fully navigable — only the padlock hints,
   tinted amber to distinguish "view only" from the greyed-out "no access" (blocked) items above. */
.nav-item.is-viewonly, .nav-subitem.is-viewonly { cursor: pointer; }
.nav-item.is-viewonly .nav-lock, .nav-subitem.is-viewonly .nav-lock, .nav-group__head.is-viewonly .nav-lock { color: var(--warn, #d9a300); opacity: .85; }

/* Read-only mode: the "view only" banner + the disabled-fieldset convention used across module pages
   (see templates/components/_readonly_banner.html.twig). A native <fieldset disabled> greys + disables
   every control inside it, so a view-only user reads the page but can't change it. */
.readonly-banner { display: flex; align-items: center; gap: .5rem; margin-bottom: 1rem; padding: .6rem .9rem;
    border-radius: 8px; font-size: 14px; color: var(--ink);
    background: color-mix(in srgb, var(--warn, #d9a300) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--warn, #d9a300) 32%, transparent); }
.readonly-banner .ico { width: 16px; height: 16px; flex: 0 0 auto; color: var(--warn, #d9a300); }
.readonly-banner strong { font-weight: 700; }
fieldset.ro-fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
fieldset.ro-fieldset[disabled] { opacity: .72; }
fieldset.ro-fieldset[disabled] * { cursor: not-allowed; }
/* Inline "view only" hint (amber eye) for per-row/action spots that aren't a full form. */
.ro-hint { display: inline-flex; align-items: center; gap: .35rem; font-size: 13px; color: var(--warn, #d9a300); }
.ro-hint .ico { width: 14px; height: 14px; flex: 0 0 auto; }
/* Padlocked action buttons (data-action="locked-nav#deny") — look disabled (muted + not-allowed
   cursor) but stay clickable, so the click still surfaces the "permission denied" toast. A native
   `disabled` attribute would swallow the click, so we style it instead. One rule covers every
   padlocked button app-wide. */
.btn[data-action~="locked-nav#deny"] {
    opacity: .55;
    cursor: not-allowed;
    background: transparent;
    box-shadow: none;
}
.btn[data-action~="locked-nav#deny"]:hover {
    opacity: .55;
    background: transparent;
    color: inherit;
    border-color: inherit;
}
/* A locked action button (e.g. Delete on a verified document): looks disabled but stays
   clickable so the click surfaces the explanatory toast. Keep it neutral/muted, not danger-red. */
.btn.is-locked-action, .btn.is-locked-action:hover {
    opacity: .5;
    cursor: not-allowed;
    background: transparent;
    box-shadow: none;
    color: var(--muted);
    border-color: var(--line);
}
.nav-subitem:hover { background: rgba(255,255,255,.07); color: #fff; text-decoration: none; }
.nav-subitem:hover .nav-subitem__icon { color: var(--accent); opacity: 1; }
.nav-subitem.is-active { background: var(--brand); color: #fff; }
.nav-subitem.is-active .nav-subitem__icon { color: #fff; opacity: 1; }

/* Nested subgroup (one level deeper than a subitem, e.g. Finance → Dashboards). */
.nav-subgroup { display: block; }
.nav-subgroup > summary { list-style: none; cursor: pointer; }
.nav-subgroup > summary::-webkit-details-marker { display: none; }
.nav-subgroup > summary::marker { content: ""; }
.nav-subgroup__head { padding-right: 10px; }
.nav-subgroup__chev { width: 15px; height: 15px; opacity: .55; flex: 0 0 auto; margin-left: auto; transition: transform .15s ease; }
.nav-subgroup[open] > summary .nav-subgroup__chev { transform: rotate(90deg); }
.nav-subgroup.is-current > summary { color: #fff; }
.nav-subgroup__items { display: flex; flex-direction: column; gap: 1px; padding: 1px 0 2px; }
.nav-subitem--nested { padding-left: 52px; height: 32px; font-size: 12.5px; }
.shell.is-collapsed .nav-subgroup__chev { display: none; }

/* Collapsed rail: groups become hover fly-out panels (each sub-item keeps its icon). */
.shell.is-collapsed .sidebar,
.shell.is-collapsed .sidebar__nav { overflow: visible; }
/* Lift the collapsed rail's whole stacking context above the sticky top bar (z-index 20) and
   page content — otherwise the fly-out panels (z-index 60 *within* the sidebar's context) still
   render BEHIND those page elements. Stays below the mobile drawer (300), modals (1000+) and
   Select2 (2000). Only in collapsed mode, where the fly-outs overhang the content. */
.shell.is-collapsed .sidebar { z-index: 100; }
.shell.is-collapsed .nav-group { position: relative; }
.shell.is-collapsed .nav-group > summary { justify-content: center; padding: 0; }
.shell.is-collapsed .nav-group__items {
  display: none;
  position: absolute; left: 100%; top: 0; z-index: 60;
  min-width: 232px; padding: 8px; gap: 1px;
  background: var(--navy-soft);
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 0 var(--radius-card) var(--radius-card) 0;
  box-shadow: 0 14px 32px rgba(0, 0, 0, .5);
}
.shell.is-collapsed .nav-group:hover > .nav-group__items,
.shell.is-collapsed .nav-group:focus-within > .nav-group__items { display: flex; }
.shell.is-collapsed .nav-group__title { display: block; font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: #647C95; padding: 4px 10px 8px; }
.shell.is-collapsed .nav-subitem { padding: 0 10px; }

/* Main column + top bar */
.shell__main { display: flex; flex-direction: column; min-width: 0; }
.topbar { position: sticky; top: 0; z-index: 20; height: var(--topbar-h); flex: 0 0 auto; background: var(--card); border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 16px; padding: 0 20px; }
.topbar__search { flex: 1 1 auto; min-width: 0; max-width: 520px; position: relative; }
.topbar__search .input { padding-left: 40px; background: var(--bg); min-height: 40px; }
.topbar__search .lead { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--faint); width: 18px; height: 18px; pointer-events: none; }
.topbar__search .kbd { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); font-size: 11px; color: var(--muted); background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: 2px 6px; pointer-events: none; }
.topbar__spacer { flex: 1 1 auto; }
.topbar__actions { display: flex; align-items: center; gap: 6px; }

.iconbtn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px; border-radius: var(--radius-control); border: 1px solid transparent; background: none; color: var(--muted); cursor: pointer; }
.iconbtn:hover { background: var(--bg); color: var(--ink); }
.iconbtn__badge { position: absolute; top: 5px; right: 5px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px; background: var(--danger); color: #fff; font-size: 10px; line-height: 16px; text-align: center; }

.user-chip { display: flex; align-items: center; gap: 10px; padding: 4px 10px 4px 4px; border-radius: var(--radius-pill); border: 1px solid var(--line); background: var(--card); cursor: pointer; }
.user-chip:hover { background: var(--bg); }
.avatar { width: 32px; height: 32px; border-radius: 50%; background: var(--brand); color: #fff; display: inline-flex; align-items: center; justify-content: center; font-family: var(--font-display); font-weight: 600; font-size: 13px; flex: 0 0 auto; }
.user-chip__meta { line-height: 1.15; text-align: left; }
.user-chip__name { font-size: 13px; color: var(--ink); font-weight: 500; }
.user-chip__role { font-size: 11px; color: var(--muted); }

/* Dropdown (user chip) */
.dropdown { position: relative; }
.dropdown__menu { position: absolute; right: 0; top: calc(100% + 6px); min-width: 210px; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-card); box-shadow: var(--shadow-card); padding: 6px; display: none; z-index: 30; }
.dropdown__menu.is-open { display: block; }
.dropdown__item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 10px; border-radius: 6px; color: var(--text); font-size: 14px; background: none; border: none; cursor: pointer; text-align: left; }
.dropdown__item:hover { background: var(--bg); color: var(--ink); text-decoration: none; }
.dropdown__sep { height: 1px; background: var(--line); margin: 6px 4px; }

/* Notifications bell dropdown */
.dropdown__menu--wide { min-width: 320px; max-width: 360px; max-height: 70vh; overflow-y: auto; }
.dropdown__title { font-size: 12px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); padding: 6px 10px 8px; margin: 0; }
.dropdown__empty { color: var(--faint); font-size: 13px; padding: 6px 10px 12px; margin: 0; }
.notif { margin: 0; }
.notif__item { display: flex; flex-direction: column; gap: 2px; width: 100%; padding: 9px 10px; border-radius: 6px; background: none; border: none; cursor: pointer; text-align: left; }
.notif__item:hover { background: var(--bg); }
.notif__msg { font-size: 13px; color: var(--ink); line-height: 1.35; }
.notif__time { font-size: 11px; color: var(--faint); font-variant-numeric: tabular-nums; }

/* Compliance checklist grid (Collections pickup form) */
.check-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 16px; }
@media (max-width: 700px) { .check-grid { grid-template-columns: 1fr; } }
.check-item { display: flex; align-items: flex-start; gap: 8px; font-size: 14px; color: var(--text); cursor: pointer; }
.check-item input { margin-top: 3px; }
.order-readout { margin-top: 8px; padding: 12px 14px; background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-control); }

/* Content canvas + right rail */
.shell__content { flex: 1 1 auto; display: flex; gap: 24px; padding: 24px; align-items: flex-start; }
.shell__canvas { flex: 1 1 auto; min-width: 0; }
.shell__rail { flex: 0 0 320px; display: flex; flex-direction: column; gap: 16px; }
@media (max-width: 1100px) { .shell__rail { display: none; } }
@media (max-width: 720px) { .shell__content { padding: 16px; } }

/* ==========================================================================
   Login — split dark/light panels (standalone, not the shell)
   ========================================================================== */
.login { min-height: 100vh; display: grid; grid-template-columns: 1.05fr 1fr; }
@media (max-width: 880px) { .login { grid-template-columns: 1fr; } .login__brandpanel { display: none; } }

.login__brandpanel { position: relative; background: var(--navy); color: #fff; overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; gap: 32px; padding: 48px; }
.login__brandpanel::before { content: ""; position: absolute; inset: 0; background: radial-gradient(120% 80% at 78% 18%, rgba(43,164,219,.20), transparent 58%), linear-gradient(160deg, var(--navy) 0%, var(--navy-deep) 100%); }
.login__brandpanel > * { position: relative; z-index: 1; }
.login__logo { width: 200px; color: #fff; }
.login__logo svg { width: 100%; height: auto; display: block; }
.login__headline { font-family: var(--font-display); font-weight: 700; font-size: 34px; line-height: 1.2; max-width: 15ch; }
.login__headline .accent { color: var(--accent); }
.login__props { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.login__prop { display: flex; align-items: center; gap: 14px; color: #C7D6E5; font-size: 14px; padding: 8px 0; position: relative; }
.login__prop .icon-badge { width: 38px; height: 38px; background: rgba(43,164,219,.16); color: var(--accent); }
.login__prop + .login__prop .icon-badge::before { content: ""; position: absolute; left: 19px; top: -16px; width: 1px; height: 16px; background: rgba(199,214,229,.25); }
.login__rig { position: absolute; left: 0; right: 0; bottom: 0; color: #16314C; opacity: .6; }
.login__rig svg { width: 100%; height: auto; display: block; }

.login__formpanel { position: relative; background: var(--card); display: flex; align-items: center; justify-content: center; padding: 40px 24px; }
.login__toggle { position: absolute; top: 18px; right: 18px; }
.login__form { width: 100%; max-width: 380px; }
.login__form h1 { font-size: 26px; }
.login__form .sub { color: var(--muted); margin: 6px 0 24px; }
.login__or { display: flex; align-items: center; gap: 12px; color: var(--faint); font-size: 12px; margin: 18px 0; text-transform: uppercase; letter-spacing: .06em; }
.login__or::before, .login__or::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.login__foot { margin-top: 28px; font-size: 12px; color: var(--muted); text-align: center; }
.checkbox-row { display: flex; align-items: center; justify-content: space-between; margin: 6px 0 18px; font-size: 13px; color: var(--text); }
.checkbox-row label { display: flex; align-items: center; gap: 8px; cursor: pointer; }

.theme-toggle { display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px; border-radius: var(--radius-pill); border: 1px solid var(--line); background: var(--card); color: var(--muted); cursor: pointer; }
.theme-toggle:hover { color: var(--brand); border-color: var(--brand); }
.theme-toggle .ico { width: 18px; height: 18px; }
.theme-toggle .ico--sun { display: none; }
html[data-theme="dark"] .theme-toggle .ico--moon { display: none; }
html[data-theme="dark"] .theme-toggle .ico--sun { display: inline-block; }

/* ==========================================================================
   Dashboard
   ========================================================================== */
.dash-greeting { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 20px; }
.dash-greeting h1 { font-size: 26px; }
.dash-greeting p { color: var(--muted); margin: 4px 0 0; }

.kpi-row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
@media (max-width: 1280px) { .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .kpi-row { grid-template-columns: minmax(0, 1fr); } }
.kpi { display: flex; gap: 14px; align-items: flex-start; }
.kpi .icon-badge { width: 48px; height: 48px; }
.kpi .icon-badge svg { width: 22px; height: 22px; }
.kpi__label { font-size: 13px; color: var(--muted); }
.kpi__value { font-family: var(--font-display); font-weight: 700; font-size: 27px; color: var(--ink); line-height: 1.15; margin: 2px 0; font-variant-numeric: tabular-nums; }
.kpi__sub { font-size: 12px; color: var(--muted); }
.kpi__sub--link { color: var(--accent); }
.kpi__sub--up { color: var(--success-ink); display: inline-flex; align-items: center; gap: 4px; }

.dash-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 16px; margin-top: 16px; }
@media (max-width: 980px) { .dash-grid { grid-template-columns: minmax(0, 1fr); } }

.card-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.card-head h3 { font-size: 16px; }
.card-head .sel { font-size: 13px; color: var(--muted); display: inline-flex; align-items: center; gap: 6px; }

.chart-box { position: relative; height: 240px; }
.chart-box--tall { height: 260px; }

/* Donut + legend. Flex-wrap so the legend sits beside the donut when there's room but drops
   BELOW it (taking the full card width) when the card is too narrow — otherwise the legend
   value strings ("1,500,000 L (60.0%)") can't shrink and spill past the card's right edge in
   the cramped dashboard column. */
.donut-split { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; }
.donut-wrap { position: relative; width: 180px; height: 200px; flex: 0 0 auto; }
.donut-center { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; pointer-events: none; }
.donut-center .big { font-family: var(--font-display); font-weight: 700; font-size: 22px; color: var(--ink); }
.donut-center .lbl { font-size: 12px; color: var(--muted); }
.legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; flex: 1 1 170px; min-width: 0; }
.legend li { display: flex; align-items: center; gap: 10px; font-size: 13px; flex-wrap: wrap; }
.legend .dot { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto; }
.legend .lg-name { color: var(--text); min-width: 0; }
.legend .lg-val { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }

/* Transactions */
.tx-amount { text-align: right; font-variant-numeric: tabular-nums; color: var(--ink); }
.tx-type { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: var(--radius-pill); background: var(--brand-tint); color: var(--brand); }
.tx-type svg { width: 17px; height: 17px; }

/* Right rail widgets */
.rail-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-card); box-shadow: var(--shadow-card); padding: 18px; }
.rail-card > h3 { font-size: 16px; margin-bottom: 12px; }
.status-list { display: flex; flex-direction: column; gap: 6px; }
.status-row { display: flex; align-items: center; gap: 12px; padding: 8px 0; }
.status-row .meta { line-height: 1.2; }
.status-row .meta .t { font-size: 14px; color: var(--ink); }
.status-row .meta .s { font-size: 12px; color: var(--accent); }
.status-row .count { margin-left: auto; font-family: var(--font-display); font-weight: 700; font-size: 18px; color: var(--ink); }
.status-row .icon-badge { width: 38px; height: 38px; }
.icon-badge--success { background: var(--success-tint); color: var(--success-ink); }
.icon-badge--warning { background: var(--warning-tint); color: var(--warning-ink); }
.icon-badge--danger  { background: var(--danger-tint);  color: var(--danger-ink); }
.icon-badge--info    { background: var(--brand-tint);   color: var(--brand); }

/* Gauge */
.gauge-wrap { position: relative; height: 130px; margin-top: 6px; }
.gauge-center { position: absolute; left: 0; right: 0; bottom: 6px; text-align: center; pointer-events: none; }
.gauge-center .big { font-family: var(--font-display); font-weight: 700; font-size: 26px; color: var(--ink); }
.gauge-center .lbl { font-size: 12px; color: var(--muted); }
.settle-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; text-align: center; margin-top: 8px; }
.settle-stats .n { font-family: var(--font-display); font-weight: 700; font-size: 20px; }
.settle-stats .k { font-size: 11px; color: var(--muted); }
.settle-stats .paid .n { color: var(--success-ink); }
.settle-stats .partial .n { color: var(--warning-ink); }
.settle-stats .unpaid .n { color: var(--danger-ink); }

/* Quick actions */
.quick-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.quick-tile { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 12px 6px; border-radius: var(--radius-control); border: 1px solid var(--line); background: var(--card); color: var(--text); text-decoration: none; text-align: center; transition: border-color .15s ease, background .15s ease; }
.quick-tile:hover { border-color: var(--brand); background: color-mix(in srgb, var(--brand) 5%, transparent); text-decoration: none; }
.quick-tile .ico-sq { width: 38px; height: 38px; border-radius: 10px; background: var(--brand-tint); color: var(--brand); display: inline-flex; align-items: center; justify-content: center; }
.quick-tile .ico-sq svg { width: 19px; height: 19px; }
.quick-tile .qt-label { font-size: 12px; color: var(--text); }

/* ==========================================================================
   Module pages (lists, forms, detail)
   ========================================================================== */
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 20px; flex-wrap: wrap; }
.page-head h1 { font-size: 24px; }
.page-head .page-sub { color: var(--muted); margin-top: 4px; font-size: 13px; }
.page-head__actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

.backlink { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); margin-bottom: 10px; }
.backlink:hover { color: var(--brand); text-decoration: none; }
.backlink .ico { width: 16px; height: 16px; transform: rotate(180deg); }

.empty { color: var(--muted); padding: 28px 4px; text-align: center; }

.table .type-badge { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: var(--radius-pill); background: var(--brand-tint); color: var(--brand); }
.table .type-badge svg { width: 16px; height: 16px; }
.table .ref { font-family: var(--font-body); color: var(--ink); font-weight: 500; }
.table .ref a { color: var(--ink); }
.table .ref a:hover { color: var(--brand); }

/* Forms */
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 16px; }
.form-grid .field--full { grid-column: 1 / -1; }
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }
select.input { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236B7A8D' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; padding-right: 36px; }
.form-actions { margin-top: 18px; display: flex; gap: 10px; flex-wrap: wrap; }
.help-text { color: var(--faint); font-size: 12px; margin-top: 10px; }

.line-card { border: 1px solid var(--line); border-radius: var(--radius-control); padding: 12px 14px; margin-bottom: 10px; }
.line-card .leg { font-size: 12px; color: var(--muted); margin-bottom: 10px; }

/* Totals summary (sales) */
.totals { max-width: 20rem; margin-left: auto; }
.totals .row { display: flex; justify-content: space-between; padding: 5px 0; font-size: 14px; }
.totals .row span:last-child { font-variant-numeric: tabular-nums; }
.totals .row--grand { font-weight: 700; color: var(--ink); border-top: 1px solid var(--line); margin-top: 4px; padding-top: 8px; }
.totals .row--due { font-weight: 700; }
/* The disbursement note uses `.totals__row` (BEM) with the same intent as `.totals .row`. */
.totals__row { display: flex; justify-content: space-between; gap: 1rem; padding: 5px 0; font-size: 14px; }
.totals__row span:last-child { font-variant-numeric: tabular-nums; }
.totals__row--grand { font-weight: 700; color: var(--ink); border-top: 1px solid var(--line); margin-top: 4px; padding-top: 8px; }

/* Detail grid on the disbursement note — spread fields across the width instead of one column. */
.kv-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px 28px; }
.kv-grid .kv--full { grid-column: 1 / -1; }
/* Horizontal metric strip (Payment / Reconciliation summaries) — uses the width rather than a
   narrow right-aligned stack. */
.note-metrics { display: flex; flex-wrap: wrap; gap: 12px 40px; align-items: flex-end; margin-bottom: 1rem; }
.note-metrics .kv__v { font-size: 16px; font-weight: 600; }
.note-metrics__status { margin-left: auto; align-self: center; }
/* Each workstream block inside the Line-items tab (flat separators, not nested cards). */
.ws-block + .ws-block { margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--line); }
/* Second sub-section heading inside a combined tab panel (e.g. Signatures under Approval). */
.note-divider { margin-top: 28px; padding-top: 22px; border-top: 1px solid var(--line); }

.banner { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: var(--radius-card); background: var(--success-tint); color: var(--success-ink); }
.banner .icon-badge { background: rgba(31,160,107,.22); color: var(--success-ink); width: 38px; height: 38px; }

/* Checkbox grid (role assignment) */
.checks { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px 14px; }
@media (max-width: 560px) { .checks { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.checks label { display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--text); cursor: pointer; padding: 6px 0; }
.check-row { display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--text); cursor: pointer; }

/* ---- User Management Pass 1: profile, admin edit, audit history ---- */

/* Larger avatar for the profile identity block */
.avatar--lg { width: 56px; height: 56px; font-size: 20px; }

/* Profile + admin-edit two-column layout (form left, context right) */
.profile-grid { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 20px; align-items: start; }
@media (max-width: 920px) { .profile-grid { grid-template-columns: 1fr; } }

.profile-id { display: flex; align-items: center; gap: 14px; padding-bottom: 16px; margin-bottom: 16px; border-bottom: 1px solid var(--line); }
.profile-id__name { font-family: var(--font-display); font-weight: 700; font-size: 18px; color: var(--ink); }
.profile-id__email { font-size: 13px; }

.card-title { font-family: var(--font-display); font-weight: 600; font-size: 16px; color: var(--ink); margin-bottom: 4px; }

/* Key/value description list (read-only org panel) */
.kv { display: grid; gap: 2px; margin-top: 12px; }
.kv > div { display: grid; grid-template-columns: 130px minmax(0, 1fr); gap: 12px; align-items: baseline; padding: 7px 0; border-top: 1px solid var(--line); }
.kv > div > *:last-child { min-width: 0; overflow-wrap: anywhere; }
.kv > div:first-child { border-top: 0; }
.kv dt { font-size: 12px; color: var(--muted); }
.kv dd { font-size: 14px; color: var(--text); font-variant-numeric: tabular-nums; }

/* Key/value spans (KPI cells, banking row). Stack the label above the value so the label and the
   "R …" amount don't run together (e.g. "PAYE" + "R 22 851.99"). */
.kv__k { display: block; font-size: 12px; color: var(--muted); margin-bottom: 2px; }
.kv__v { display: block; font-size: 14px; color: var(--text); font-variant-numeric: tabular-nums; }
.kpi-row .kv__v { font-size: 18px; font-weight: 500; }

/* Statutory config: each tax year is a collapsible card — collapsed shows just the header. */
.stat-year { padding: 0; }
.stat-year > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 16px 18px; }
.stat-year > summary::-webkit-details-marker { display: none; }
.stat-year > summary:hover { background: var(--bs-tertiary-bg, var(--pale)); border-radius: 12px; }
.stat-year__title { font-family: var(--font-display); font-weight: 600; font-size: 15px; }
.stat-year__dates { font-weight: 400; }
.stat-year__chev { margin-left: auto; color: var(--bs-secondary-color, var(--muted)); transition: transform .15s ease; }
.stat-year[open] > summary .stat-year__chev { transform: rotate(180deg); }
.stat-year[open] > summary { border-bottom: 1px solid var(--bs-border-color, var(--line)); border-radius: 0; }
.stat-year__body { padding: 16px 18px 18px; }
/* The .card display override breaks native <details> hiding, so collapse the body explicitly. */
.stat-year:not([open]) > .stat-year__body { display: none; }

/* Field section legend inside the admin edit form */
.field-group { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line); }
.field-group:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }
.field-group__title { font-size: 12px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); margin-bottom: 12px; }

/* Repeating emergency-contact rows (repeater_controller): Name / Relationship / Phone + Remove. */
.ec-row { display: grid; grid-template-columns: 1fr 1fr 1fr auto; gap: 12px; align-items: end; margin-bottom: 12px; }
.ec-row > label { margin: 0; }
.ec-row .form-label { display: block; }
.ec-row__remove { white-space: nowrap; }
@media (max-width: 720px) { .ec-row { grid-template-columns: 1fr; } .ec-row__remove { justify-self: start; } }

/* Company-assets tab: assigned-asset cards + their return form. */
.asset-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 4px; }
.asset-card { display: flex; flex-wrap: wrap; gap: 12px 18px; align-items: end; justify-content: space-between; padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius-card); background: var(--bg); }
.asset-card__info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.asset-card__name { font-weight: 600; color: var(--ink); }
.asset-return { display: grid; grid-template-columns: 170px minmax(140px, 1fr) auto; gap: 10px; align-items: end; flex: 1 1 360px; }
.asset-return > label { margin: 0; }
.asset-return .form-label { display: block; }
@media (max-width: 720px) { .asset-return { grid-template-columns: 1fr; } }

/* Documents tab: per-type upload row (file + expiry date + button). */
.doc-upload { display: flex; flex-wrap: wrap; gap: 12px; align-items: end; margin-top: 4px; }
.doc-upload__field { margin: 0; }
.doc-upload__field .form-label { display: block; }

/* Centred employee create form + its placeholder tabs. */
.emp-form-wrap { max-width: 64rem; margin: 0 auto; }
.empty-tab { padding: 6px 0 4px; }

/* Status actions row on the admin edit screen */
.status-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }

/* Audit history timeline (admin edit right column) */
.timeline { list-style: none; margin: 12px 0 0; padding: 0; }
.timeline li { position: relative; padding: 0 0 16px 22px; border-left: 2px solid var(--line); }
.timeline li:last-child { padding-bottom: 0; border-left-color: transparent; }
.timeline li::before { content: ""; position: absolute; left: -7px; top: 2px; width: 12px; height: 12px; border-radius: 50%; background: var(--brand); border: 2px solid var(--card); }
.timeline__head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.timeline__type { font-weight: 600; font-size: 13px; color: var(--ink); }
.timeline__time { font-size: 12px; color: var(--faint); }
.timeline__meta { font-size: 12px; color: var(--muted); margin-top: 3px; }
.timeline__reason { font-size: 13px; color: var(--text); margin-top: 3px; font-style: italic; }
.timeline__empty { color: var(--faint); font-size: 13px; margin-top: 12px; }

/* Tabs (tabs_controller) — used on the new-customer form */
/* Tab strips scroll horizontally instead of wrapping/overflowing when they run out of room
   (e.g. the 5–6 tab forms on a tablet) — the scrollbar is hidden for a clean look. */
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin-bottom: 18px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none; }
.tabs::-webkit-scrollbar { height: 0; display: none; }
.tab { appearance: none; background: none; border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px; padding: 10px 14px; font-family: var(--font-body); font-size: 14px; color: var(--muted); cursor: pointer; flex: 0 0 auto; white-space: nowrap; }
.tab:hover { color: var(--ink); }
.tab.is-active { color: var(--brand); border-bottom-color: var(--brand); font-weight: 500; }
.tab__hint { color: var(--faint); font-size: 12px; }
.tab-panel[hidden] { display: none; }

/* Pre-JS / failed-JS fallback: until the tabs controller adds `.tabs-ready`, show only the
   FIRST panel instead of stacking every panel (which reads as a broken page). Once the
   controller has initialised, its `hidden` attribute governs visibility as normal. */
.tab-panel ~ .tab-panel { display: none; }
.tabs-ready .tab-panel { display: block; }
.tabs-ready .tab-panel[hidden] { display: none; }

/* Four-column form grid (the contract Shipment Details section) */
.form-grid--4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px 16px; }
@media (max-width: 1100px) { .form-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .form-grid--4 { grid-template-columns: 1fr; } }

/* Input + deferred "add" button (the "+" lookups — inline create is a later slice) */
.field-add { display: flex; align-items: flex-end; gap: 8px; }
.field-add .field { flex: 1 1 auto; }
.btn-add { flex: 0 0 auto; width: 40px; height: 40px; border-radius: var(--radius-control); border: 1px solid var(--line); background: var(--brand); color: #fff; font-size: 20px; line-height: 1; cursor: pointer; }
.btn-add:disabled { background: var(--faint); cursor: not-allowed; opacity: .7; }

/* Inline Yes/No radio row (Sales Broker) */
.radio-row { display: flex; align-items: center; gap: 16px; height: 40px; }
.radio-row label { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; color: var(--text); cursor: pointer; }
.req { color: var(--danger); font-weight: 700; }

/* Section sub-head inside a multi-section form (e.g. the order-details groups) */
.section-head { font-family: var(--font-display); font-weight: 600; font-size: 15px; color: var(--ink); margin: 0 0 4px; }

/* ── Accessibility helper ─────────────────────────────────────────────────── */
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ── Global loading overlay ───────────────────────────────────────────────── */
.loading-overlay {
    position: fixed; inset: 0; z-index: 1000;
    display: flex; align-items: center; justify-content: center;
    background: color-mix(in srgb, var(--navy) 38%, transparent);
    backdrop-filter: blur(1.5px);
    /* Inactive = invisible AND click-through. `display:flex` here defeats the [hidden]
       attribute, so interaction must be gated on visibility + pointer-events, never on
       opacity alone (a transparent overlay would still swallow every click). */
    opacity: 0; visibility: hidden; pointer-events: none;
    transition: opacity 180ms ease, visibility 180ms ease;
}
.loading-overlay.is-active { opacity: 1; visibility: visible; pointer-events: auto; }
.loading-overlay__box {
    display: flex; flex-direction: column; align-items: center; gap: 12px;
    padding: 22px 28px; background: var(--card); color: var(--ink);
    border: 1px solid var(--line); border-radius: var(--radius-card); box-shadow: var(--shadow-card);
}
.loading-overlay__label { font-family: var(--font-display); font-weight: 600; font-size: 14px; color: var(--ink); }
.loading-spinner {
    width: 34px; height: 34px; border-radius: 50%;
    border: 3px solid var(--line); border-top-color: var(--brand);
    animation: loading-spin 720ms linear infinite;
}
@keyframes loading-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    .loading-overlay { transition: none; }
    .loading-spinner { animation: none; border-top-color: var(--brand); }
}

/* ── SweetAlert2 theme (follows [data-theme] via the tokens; light + dark) ──── */
.swal2-container { z-index: 1100; }
.swal-pop, .swal2-popup.swal-pop {
    background: var(--card); color: var(--text);
    border: 1px solid var(--line); border-radius: var(--radius-card); box-shadow: var(--shadow-card);
}
.swal-title, .swal2-popup .swal-title { font-family: var(--font-display); color: var(--ink); }
.swal-text, .swal2-popup .swal-text { color: var(--text); font-family: var(--font-body); }
.swal2-popup .swal2-actions { gap: 10px; }
/* Toasts */
.swal2-toast.swal-toast {
    background: var(--card); color: var(--text);
    border: 1px solid var(--line); border-radius: var(--radius-card); box-shadow: var(--shadow-card);
}
.swal2-toast .swal-toast__title { color: var(--ink); font-family: var(--font-body); font-size: 13.5px; }
.swal2-toast .swal2-timer-progress-bar { background: var(--brand); }
/* Icon colours mapped to status tokens (both modes) */
.swal2-icon.swal2-success { border-color: var(--success); color: var(--success); }
.swal2-icon.swal2-success [class^='swal2-success-line'] { background-color: var(--success); }
.swal2-icon.swal2-success .swal2-success-ring { border-color: color-mix(in srgb, var(--success) 30%, transparent); }
.swal2-icon.swal2-error { border-color: var(--danger); color: var(--danger); }
.swal2-icon.swal2-error [class^='swal2-x-mark-line'] { background-color: var(--danger); }
.swal2-icon.swal2-warning { border-color: var(--warning); color: var(--warning); }
.swal2-icon.swal2-info, .swal2-icon.swal2-question { border-color: var(--brand); color: var(--brand); }
/* Toasts colour-coded by message category (success/info/warning/error) — background per category,
   white text + icon for contrast (both themes). Applies to ALL toasts (flashes, live events, etc.);
   the neutral .swal-toast base above is overridden here. */
.swal2-toast.swal-toast--success { background: #15803d !important; border-color: #0f6a32 !important; }
.swal2-toast.swal-toast--info    { background: #1d4ed8 !important; border-color: #1b45bd !important; }
.swal2-toast.swal-toast--warning { background: #b45309 !important; border-color: #92400e !important; }
.swal2-toast.swal-toast--error   { background: #b91c1c !important; border-color: #991b1b !important; }
.swal2-toast[class*="swal-toast--"] { color: #fff !important; }
.swal2-toast[class*="swal-toast--"] .swal-toast__title { color: #fff !important; }
.swal2-toast[class*="swal-toast--"] .swal-toast__close { color: #fff !important; opacity: .9; }
.swal2-toast[class*="swal-toast--"] .swal2-timer-progress-bar { background: rgba(255, 255, 255, .55) !important; }
.swal2-toast[class*="swal-toast--"] .swal2-icon { border-color: #fff !important; color: #fff !important; }
.swal2-toast[class*="swal-toast--"] .swal2-icon [class^='swal2-success-line'],
.swal2-toast[class*="swal-toast--"] .swal2-icon [class^='swal2-x-mark-line'] { background-color: #fff !important; }
.swal2-toast[class*="swal-toast--"] .swal2-icon .swal2-success-ring { border-color: rgba(255, 255, 255, .4) !important; }

/* ==========================================================================
   Bootstrap 5 bridge — map the brand design tokens onto Bootstrap's CSS
   variables so Bootstrap + DataTables (bs5) render in the Umtongata palette
   and follow light/dark. Bootstrap CSS is loaded BEFORE this sheet (app.js),
   so these overrides win. Dark mode flips via data-bs-theme (set alongside
   data-theme by the no-flash boot script + theme controller).
   ========================================================================== */
:root {
  --bs-primary: var(--brand);
  --bs-primary-rgb: 28, 143, 191;
  --bs-link-color: var(--accent);
  --bs-link-color-rgb: 43, 164, 219;
  --bs-link-hover-color: var(--brand-hover);
  --bs-body-bg: var(--bg);
  --bs-body-color: var(--text);
  --bs-emphasis-color: var(--ink);
  --bs-secondary-color: var(--muted);
  --bs-border-color: var(--line);
  --bs-secondary-bg: var(--bg);
  --bs-tertiary-bg: var(--bg);
  --bs-font-sans-serif: var(--font-body);
  --bs-body-font-size: 14px;
  --bs-border-radius: var(--radius-control);
  --bs-border-radius-sm: 6px;
}
[data-bs-theme="dark"] {
  --bs-body-bg: var(--bg);
  --bs-body-color: var(--text);
  --bs-emphasis-color: var(--ink);
  --bs-secondary-color: var(--muted);
  --bs-border-color: var(--line);
  --bs-secondary-bg: var(--navy-soft);
  --bs-tertiary-bg: var(--navy);
}

/* Collision guard: Bootstrap's grid `.row` adds negative gutters/margins that would
   leak into the sales totals (a `.totals .row` flex line, not a grid row). */
.totals .row { margin: 0; --bs-gutter-x: 0; }

/* ===== DataTables (bs5) — fit inside our cards, follow the tokens =========== */
.dt-container { font-family: var(--font-body); font-size: 14px; color: var(--text); }
.dt-container .dt-search { display: flex; justify-content: flex-end; margin-bottom: 12px; }
.dt-container .dt-search input.form-control { max-width: 280px; }
.dt-container .dt-length { margin-bottom: 12px; color: var(--muted); }
.dt-container .dt-length select.form-select { width: auto; display: inline-block; }
.dt-container .dt-info { color: var(--muted); font-size: 13px; padding-top: 12px; }
.dt-container .dt-paging { padding-top: 8px; }
.dt-container .dt-paging .page-link { color: var(--text); }
.dt-container .dt-paging .active > .page-link { background: var(--brand); border-color: var(--brand); color: #fff; }
/* The DataTables-managed table keeps our cell styling; let the wrapper breathe. */
.dt-container table.table { margin-bottom: 0; }
.dt-container table.table > :not(caption) > * > * { background: transparent; }

/* Top-bar search keyboard hint: a subtle ⌘K / Ctrl K chip on the input's right edge,
   not a prominent gray addon (border-left dropped so it merges into the field). */
.topbar__kbd { background: transparent; border-left: 0; padding-left: 4px; padding-right: 10px; }
.topbar__kbd kbd {
  background: var(--bg); color: var(--muted); border: 1px solid var(--line);
  border-radius: 4px; padding: 1px 6px; font-size: 11px; font-family: var(--font-body);
  line-height: 1.4; box-shadow: none; white-space: nowrap;
}

/* ── Permissions matrix (Slice F0) ─────────────────────────────────────────── */
.matrix-grid { display: grid; grid-template-columns: 1fr 320px; gap: 1.25rem; align-items: start; }
@media (max-width: 1100px) { .matrix-grid { grid-template-columns: 1fr; } }
.matrix-table th.matrix-role { font-size: 12px; white-space: nowrap; text-align: center; vertical-align: bottom; }
.matrix-table td.matrix-cell { text-align: center; padding: .35rem; }
.matrix-table td.matrix-perm { min-width: 220px; }
.matrix-module td { background: var(--brand-tint); color: var(--ink); font-weight: 600; text-transform: uppercase; font-size: 12px; letter-spacing: .04em; }
[data-bs-theme="dark"] .matrix-module td { background: var(--navy-soft); color: #fff; }
.matrix-table select.cell { min-width: 104px; }
select.cell--allowed { border-color: var(--success); color: var(--success-ink); font-weight: 600; }
select.cell--view_only { border-color: var(--warning); color: var(--warning-ink); }
select.cell--no_access { color: var(--muted); }
.matrix-side { display: flex; flex-direction: column; gap: 1.25rem; }
.matrix-side .card-title { margin: 0 0 .75rem; font-size: 16px; }

/* ── Roles matrix v2: collapsed business roles, icon cells, details rail ────── */
.matrix-toolbar { display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap; margin: 4px 0 14px; }
.matrix-legend { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; }
.legend-chip { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); }

.matrix-role__btn { display: flex; flex-direction: column; align-items: center; gap: 6px; background: none; border: 0; cursor: pointer; color: var(--muted); padding: 6px 10px; border-radius: 10px; width: 100%; }
.matrix-role__btn:hover { background: var(--brand-tint); color: var(--ink); }
.matrix-role.is-selected .matrix-role__btn { color: var(--brand); }
.matrix-role__icon { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 10px; background: var(--brand-tint); color: var(--navy); }
[data-bs-theme="dark"] .matrix-role__icon { background: var(--navy-soft); color: #fff; }
.matrix-role.is-selected .matrix-role__icon { background: var(--brand); color: #fff; }
.matrix-role__label { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; font-weight: 700; white-space: normal; max-width: 110px; line-height: 1.25; }

.matrix-module-cell { vertical-align: top; background: var(--brand-tint); min-width: 110px; text-align: center; padding-top: 14px !important; }
[data-bs-theme="dark"] .matrix-module-cell { background: var(--navy-soft); }
.matrix-module__icon { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 10px; background: var(--card); color: var(--navy); box-shadow: 0 1px 2px rgba(10,26,47,.08); }
[data-bs-theme="dark"] .matrix-module__icon { color: #fff; background: var(--navy); }
.matrix-module__label { display: block; margin-top: 6px; font-size: 11px; font-weight: 700; letter-spacing: .05em; color: var(--ink); }

.matrix-perm .matrix-desc { display: none; font-size: 12px; margin-top: 2px; }
.show-desc .matrix-perm .matrix-desc { display: block; }

/* Transposed matrix (v3): roles are ROWS (left, sticky), permissions are COLUMNS. */
.matrix-table--transposed th.matrix-perm-corner { position: sticky; left: 0; z-index: 3; background: var(--card); text-align: left; min-width: 160px; }
.matrix-table--transposed th.matrix-perm-col { text-align: center; vertical-align: bottom; min-width: 96px; padding: 8px 6px; }
.matrix-perm-col__label { display: block; font-size: 12px; font-weight: 600; color: var(--ink); line-height: 1.2; white-space: normal; }
.matrix-perm-col .matrix-desc { display: none; font-size: 11px; margin-top: 3px; color: var(--muted); }
.show-desc .matrix-perm-col .matrix-desc { display: block; }
.matrix-table--transposed th.matrix-role--row { position: sticky; left: 0; z-index: 2; background: var(--card); text-align: left; min-width: 160px; vertical-align: middle; }
.matrix-table--transposed th.matrix-role--row .matrix-role__btn { flex-direction: row; align-items: center; justify-content: flex-start; gap: 10px; }
.matrix-table--transposed th.matrix-role--row .matrix-role__label { max-width: none; text-transform: none; letter-spacing: 0; font-size: 12.5px; font-weight: 700; }
.matrix-table--transposed th.matrix-role--row .matrix-role__icon { width: 28px; height: 28px; flex-shrink: 0; }

/* Module side tabs — one permission group visible at a time */
.matrix-main { display: flex; gap: 14px; align-items: flex-start; min-width: 0; }
.module-tabs { display: flex; flex-direction: column; gap: 4px; width: 176px; flex-shrink: 0; position: sticky; top: 84px; }
.module-tab { display: flex; align-items: center; gap: 10px; border: 0; background: none; text-align: left; padding: 9px 12px; border-radius: 10px; font-size: 13px; font-weight: 600; color: var(--muted); cursor: pointer; }
.module-tab .ico { width: 16px; height: 16px; flex-shrink: 0; }
.module-tab:hover { background: var(--brand-tint); color: var(--ink); }
.module-tab.is-active { background: var(--navy); color: #fff; }
[data-bs-theme="dark"] .module-tab.is-active { background: var(--brand); }
.matrix-panels { flex: 1; min-width: 0; }
@media (max-width: 900px) { .matrix-main { flex-direction: column; } .module-tabs { position: static; flex-direction: row; flex-wrap: wrap; width: 100%; } }

.mcell { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: 50%; border: 0; cursor: pointer; padding: 0; transition: transform .08s ease; }
.mcell .ico { width: 15px; height: 15px; }
.mcell:hover { transform: scale(1.12); }
.mcell--mini { width: 22px; height: 22px; cursor: default; }
.mcell--mini:hover { transform: none; }
.mcell--allowed { background: #1FA06B; color: #fff; }
.mcell--view_only { background: #E2A02E; color: #fff; }
.mcell--no_access { background: var(--line); color: var(--muted); }
[data-bs-theme="dark"] .mcell--no_access { background: var(--navy-soft); }
.mcell--locked { background: var(--navy); color: var(--brand); cursor: default; }
.mcell--locked:hover { transform: none; }
.mcell-dash { font-weight: 800; line-height: 1; }

.role-detail__name { margin: 4px 0 6px; font-family: var(--font-display); font-weight: 700; font-size: 17px; color: var(--ink); }
.role-avatars { display: flex; gap: 4px; flex-wrap: wrap; }
.role-avatar { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: 50%; background: var(--navy); color: #fff; font-size: 11px; font-weight: 700; }
.role-avatar--more { background: var(--brand-tint); color: var(--ink); }

/* ── Filter bar (audit log, finance tabs) ──────────────────────────────────── */
.filter-bar { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-end; }
.filter-bar .mb-3 { margin-bottom: 0 !important; }
.filter-bar__actions { display: flex; gap: .5rem; }
.inline-actions { display: inline-flex; gap: .5rem; align-items: center; }

/* ── Finance dashboard + customise mode ────────────────────────────────────── */
/* 6 KPI cards wrap responsively (the landing dashboard's .kpi-row is a fixed 4). */
.fin-dash .kpi-row { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.pnl-table td, .pnl-table th { padding: .55rem .25rem; }
.pnl-table tfoot th { border-top: 2px solid var(--line); font-size: 15px; }

/* Per-card hide/show toggle — only visible while customising. */
.dash-card { position: relative; }
.card-customise-toggle { display: none; position: absolute; top: 8px; right: 8px; z-index: 2;
    font-size: 11px; font-weight: 600; line-height: 1; padding: 4px 8px; border-radius: var(--radius-pill);
    border: 1px solid var(--line); background: var(--card); color: var(--muted); cursor: pointer; }
.card-customise-toggle:hover { color: var(--ink); border-color: var(--brand); }
.card-customise-toggle .cct-show { display: none; }
.card-excluded .card-customise-toggle .cct-hide { display: none; }
.card-excluded .card-customise-toggle .cct-show { display: inline; }
.is-customising .card-customise-toggle { display: inline-flex; }
/* Hidden cards: removed from the layout normally, shown dimmed while customising. */
.dash-card.is-hidden { display: none; }
.is-customising .dash-card.card-excluded { opacity: .5; outline: 2px dashed var(--line); outline-offset: 3px; }
/* The Reset button only appears in edit mode. */
.cust-reset { display: none; }
.is-customising .cust-reset { display: inline-flex; }

/* Clickable DataTable rows (Finance clients → client detail). */
.table tbody tr.is-clickable { cursor: pointer; }
.table tbody tr.is-clickable:hover { background: var(--brand-tint); }

/* Report launcher cards (client detail → Reports tab). */
.report-cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
@media (max-width: 720px) { .report-cards { grid-template-columns: minmax(0, 1fr); } }
.report-card { display: flex; gap: 14px; align-items: flex-start; padding: 18px; border: 1px solid var(--line);
    border-radius: var(--radius-card); background: var(--card); color: inherit; text-decoration: none; transition: border-color .15s, box-shadow .15s; }
.report-card:hover { border-color: var(--brand); box-shadow: var(--shadow-card); }
.report-card__icon { color: var(--brand); flex: 0 0 auto; }
.report-card__icon svg, .report-card__icon .ico { width: 30px; height: 30px; }
.report-card__title { font-family: var(--font-display); font-weight: 600; font-size: 15px; color: var(--ink); display: flex; align-items: center; gap: 8px; }
.report-card__desc { font-size: 13px; color: var(--muted); margin: 4px 0 0; }
.report-card__badge { font-size: 10px; font-weight: 700; letter-spacing: .04em; color: var(--brand);
    border: 1px solid var(--brand); border-radius: var(--radius-pill); padding: 2px 7px; }
.report-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem; }
.report-period { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.report-period .form-label { margin: 0; }
.report-period .form-control { width: auto; }

/* Dynamic sales-order lines */
.lines-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: 8px; flex-wrap: wrap; }
.line-row { display: flex; gap: 12px; align-items: flex-start; padding: 12px; border: 1px solid var(--line);
    border-radius: var(--radius-card); margin-bottom: 10px; background: var(--canvas); }
.line-row__fields { flex: 1; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 900px) { .line-row__fields { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Pin each control to the BOTTOM of its grid cell so the row reads as one line of inputs. Without
   this a label that wraps — "Unit price (/L)" and "Line total (ZAR)" both do once the columns get
   narrow — pushes ITS control 21px below the others, and the row goes ragged exactly where it is
   hardest to read. The label grows upward instead. */
.line-row__fields > label { display: flex; flex-direction: column; justify-content: flex-end; }
/* On the input line, not floating in the middle of the row beside it. */
.line-row__remove { align-self: flex-end; white-space: nowrap; }
.line-row .line-total { background: var(--brand-tint); font-weight: 600; }

/* Invoice editor (FreshBooks-style document) */
.invoice-doc { max-width: 880px; margin-left: auto; margin-right: auto; position: relative; overflow: hidden; }

/* Diagonal payment-state watermark stamped across the (immutable) invoice document */
.inv-watermark { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; pointer-events: none; z-index: 3; }
.inv-watermark span { font-family: var(--font-display); font-weight: 800; font-size: 116px; letter-spacing: .06em; text-transform: uppercase; white-space: nowrap; transform: rotate(-26deg); color: rgba(107,122,141,.16); }
.inv-watermark--cancelled span, .inv-watermark--overdue span, .inv-watermark--declined span, .inv-watermark--expired span { color: rgba(192,57,57,.16); }
[data-theme="dark"] .inv-watermark span { color: rgba(255,255,255,.10); }
[data-theme="dark"] .inv-watermark--cancelled span, [data-theme="dark"] .inv-watermark--overdue span, [data-theme="dark"] .inv-watermark--declined span, [data-theme="dark"] .inv-watermark--expired span { color: rgba(232,120,120,.16); }
/* Neutral "Tax Invoice" watermark shown when there's no payment-state stamp (an unpaid invoice). */
.inv-watermark--doc span { color: rgba(107,122,141,.09); font-size: 92px; }
[data-theme="dark"] .inv-watermark--doc span { color: rgba(255,255,255,.07); }

/* Document title + settlement-account block + footer (mirrors the printed tax invoice). */
.inv-doctitle { font-family: var(--font-display); font-weight: 800; font-size: 26px; letter-spacing: .04em; text-transform: uppercase; color: var(--ink); margin: 2px 0 14px; }
/* Ad-hoc only: tax invoice vs pro forma, sitting just above the document title it switches. */
.inv-doctype-pick { display: flex; align-items: center; gap: 14px; margin: 2px 0 6px; font-size: 13px; }
.inv-doctype-pick .inv-k { margin-bottom: 0; }
.inv-doctype-pick label { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; cursor: pointer; }
.inv-bank { margin-top: 22px; border-top: 1px solid var(--line); padding-top: 14px; }
.inv-bank__t { border-collapse: collapse; font-size: 13px; margin-top: 6px; }
.inv-bank__t td { padding: 2px 18px 2px 0; vertical-align: top; }
.inv-foot { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; margin-top: 26px; padding-top: 12px; border-top: 1px solid var(--line); font-size: 13px; }
.inv-foot__thanks { font-family: var(--font-display); text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 600; white-space: nowrap; }
.inv-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 24px; padding-bottom: 18px; border-bottom: 2px solid var(--line); margin-bottom: 18px; }
.inv-logo { color: var(--navy); }
.inv-logo svg { width: 200px; height: auto; }
/* An UPLOADED company logo (Administration → Companies). Bounded rather than fixed-size so a
   logo of any aspect ratio keeps its proportions — unlike the brand lockup, these vary. */
.inv-logo__img { max-width: 220px; max-height: 56px; width: auto; height: auto; object-fit: contain; }
[data-theme="dark"] .inv-logo { color: #fff; }
/* The issuing company's registration number, printed under the letterhead logo (see
   templates/invoices/_logo.html.twig). Muted so it reads as letterhead detail, not document data. */
.inv-regno { margin-top: 6px; font-size: 12px; color: var(--muted); }
.inv-company { text-align: right; font-size: 13px; color: var(--muted); line-height: 1.55; }
.inv-company strong { color: var(--ink); font-size: 15px; }
.inv-meta { display: flex; justify-content: space-between; gap: 24px; flex-wrap: wrap; margin-bottom: 18px; }
.inv-k { font-size: 10px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin-bottom: 4px; display: block; }
.inv-billto { font-size: 14px; line-height: 1.6; }
.inv-fields { min-width: 280px; max-width: 330px; }
.inv-fields .mb-2 { display: block; margin-bottom: 8px; }
.inv-fields .form-label { font-size: 12px; margin-bottom: 2px; }
.inv-due { display: flex; justify-content: space-between; align-items: baseline; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line); }
.inv-due__val { font-family: var(--font-display); font-weight: 700; font-size: 22px; color: var(--ink); white-space: nowrap; }
.inv-lines td { vertical-align: top; }
/* The editor line tables are documents, not scrollable list grids — opt out of the
   `.card > .table { display:block; overflow-x:auto }` rule (higher specificity to beat it) so
   they stay full-width tables; otherwise the narrow-input adhoc/cost table's inner rows
   shrink to content and left-align. */
.card > .table.inv-lines { display: table; width: 100%; overflow: visible; }
/* A money column must never WRAP. Auto table layout hands the widest column to whichever content
   asks loudest, and on the order-backed invoice editor that squeezed "Line total" to 90px — so
   "R 20,000.00" broke across two lines and sat 21px below the rate and quantity it belongs beside.
   Nowrap makes the column claim the width the figure needs, which is the only width that is right. */
.inv-lines th.amount, .inv-lines td.amount { white-space: nowrap; }
.inv-lines td input[type="text"] { width: 100%; }
.inv-lines td.amount input { width: 100%; max-width: 150px; margin-left: auto; text-align: right; }
.inv-lines td:last-child { width: 44px; text-align: center; }
.inv-totals { max-width: 26rem; margin-left: auto; margin-top: 14px; }
.inv-totals .row, .inv-schedule .row { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 5px 0; font-size: 14px; }
.inv-totals .row span:last-child { font-variant-numeric: tabular-nums; }
.inv-totals .row--grand { font-weight: 700; color: var(--ink); border-top: 1px solid var(--line); margin-top: 4px; padding-top: 8px; }
.inv-discount { max-width: 130px; text-align: right; }
.vat-modes { display: inline-flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; font-size: 13px; }
.vat-modes label { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; cursor: pointer; }
.inv-deposit, .inv-schedule { font-size: 13px; }

.inv-dialog { border: none; border-radius: var(--radius-card); box-shadow: 0 16px 50px rgba(8,16,28,.35); padding: 22px; max-width: 360px; width: 92%; color: var(--ink); background: var(--card); }
.inv-dialog--wide { max-width: 480px; }
.inv-dialog--payments { max-width: 640px; }
.inv-dialog--payments .table td, .inv-dialog--payments .table th { padding: 7px 10px; }
.inv-dialog::backdrop { background: rgba(8,16,28,.5); }
.inv-dialog h3 { margin: 0 0 6px; font-size: 17px; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.sched-row { display: grid; grid-template-columns: 1fr 1fr auto; gap: 10px; align-items: end; margin-bottom: 10px; }
.sched-row__del { align-self: end; }
.sched-total { display: flex; justify-content: space-between; border-top: 1px solid var(--line); margin-top: 10px; padding-top: 10px; font-size: 14px; }

/* Read-only invoice view (the editor layout, fields shown as values) */
.inv-meta--view { align-items: flex-start; }
.inv-meta--view > div { font-size: 14px; line-height: 1.5; }
.inv-meta__due { text-align: right; margin-left: auto; }

/* Reconciliation summary KPIs (accrual revenue vs cash received vs profit) */
.recon-row { display: flex; gap: 20px; flex-wrap: wrap; align-items: stretch; }
.recon-summary { flex: 1 1 300px; }
.recon-chart { flex: 2 1 460px; }

/* ── Executive-overview headline cards ─────────────────────────────────────────────────────────
   Deliberately larger than the .kpi cards elsewhere: these four are the first thing read on the
   screen, and the note under each is a verdict, not decoration. The row carries its own bottom
   margin so the table below is not crowded against it. Auto-fit rather than a fixed four-up, so
   the cards reflow on a laptop and stack on a phone without a breakpoint per layout.

   THE 13.5rem MINIMUM IS MEASURED, not picked. At a 1280px viewport the content column is 957px:
   a 15rem (240px) minimum needs 1014px for four cards, so a four-card row wrapped 3+1 on the most
   common laptop width there is. 13.5rem (216px) needs 918px and leaves headroom. */
.kpi-hero-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13.5rem, 1fr));
    gap: 18px;
    margin-bottom: 28px;
}
.kpi-hero { display: flex; flex-direction: column; gap: 6px; padding: 22px 24px; position: relative; overflow: hidden; }
.kpi-hero__k { font-size: 13px; font-weight: 600; color: var(--muted); letter-spacing: .01em; }
.kpi-hero__v { font-family: var(--font-display); font-size: 34px; font-weight: 700; line-height: 1.1; color: var(--ink); }
.kpi-hero__mark { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--muted); min-height: 18px; }
.kpi-hero__mark .ico { width: 16px; height: 16px; flex: 0 0 auto; }

/* A 3px edge rather than a tinted card: the verdict has to be legible at a glance without the
   colour fighting the figure, and a full wash would make four cards look like four alerts. */
.kpi-hero::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 3px; background: transparent; }
.kpi-hero--up::before { background: var(--success); }
.kpi-hero--down::before { background: var(--danger); }
.kpi-hero--flat::before { background: var(--warning); }
.kpi-hero--up .kpi-hero__mark { color: var(--success-ink); }
.kpi-hero--down .kpi-hero__mark { color: var(--danger-ink); }
.kpi-hero--flat .kpi-hero__mark { color: var(--warning-ink); }

/* A headline card acting as a filter. Same card, plus the affordances a link owes the reader:
   something happens on hover, and the active one is unmistakable — otherwise a row of six reads
   as six statistics rather than six choices, one of which is currently in force. */
.kpi-hero--link { text-decoration: none; transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease; }
.kpi-hero--link:hover { border-color: var(--brand); box-shadow: var(--shadow-card-hover, var(--shadow-card)); transform: translateY(-1px); }
.kpi-hero--link.is-selected { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-tint); }
.kpi-hero--link.is-selected .kpi-hero__k { color: var(--brand); font-weight: 700; }
@media (prefers-reduced-motion: reduce) { .kpi-hero--link { transition: none; } .kpi-hero--link:hover { transform: none; } }

/* The dashboard's stacked cards. Without this they sit flush against each other — .card carries no
   margin of its own — so the page read as one gap under the headline row and none anywhere after.
   Same 28px as .kpi-hero-row's margin-bottom, deliberately: the space above the first card, between
   the cards and below the last one are then all the same, which is the whole point of a rhythm.
   Scoped to this page rather than added to .card globally, where it would move every screen. */
.dash-stack { display: grid; gap: 28px; margin-bottom: 28px; }

/* The active focus area on the Executive Overview. It sits in the page head rather than beside the
   objectives table on purpose: the table it filters is below the fold, so without something up here
   a focus click looks like it did nothing at all. */
.focus-chip {
    display: inline-flex; align-items: center; gap: 8px;
    margin: 10px 0 0; padding: 5px 12px 5px 10px;
    border: 1px solid var(--brand); border-radius: 999px;
    background: var(--brand-tint, transparent); color: var(--ink); font-size: 13px;
}
.focus-chip .ico { width: 15px; height: 15px; flex: 0 0 auto; color: var(--brand); }
.focus-chip a { margin-left: 2px; padding-left: 9px; border-left: 1px solid var(--line); color: var(--muted); font-size: 12px; }
.focus-chip a:hover { color: var(--ink); }
.recon-kpis { display: flex; gap: 36px; flex-wrap: wrap; }
.recon-summary .recon-kpis { flex-direction: column; gap: 18px; }
.recon-kpis__val { font-family: var(--font-display); font-size: 22px; font-weight: 700; color: var(--ink); margin-top: 2px; }

/* Create-payment overlay modal (custom, not <dialog>, so Select2 dropdowns render above it) */
.pay-modal { position: fixed; inset: 0; z-index: 1090; display: none; align-items: flex-start; justify-content: center; background: rgba(8,16,28,.5); padding: 6vh 16px; overflow-y: auto; }
.pay-modal.is-open { display: flex; }
.pay-modal__panel { background: var(--card); color: var(--ink); border-radius: var(--radius-card); box-shadow: 0 16px 50px rgba(8,16,28,.35); padding: 24px; width: 100%; max-width: 480px; }
.pay-modal__panel h3 { margin: 0 0 14px; }
.select2-container--open { z-index: 2000; }
.select2-dropdown { z-index: 2000; }

/* Two-column totals ledger (label · [due] · value, right-aligned) */
.inv-ledger { margin: 16px 0 0 auto; border-collapse: collapse; min-width: 380px; }
.inv-ledger td { padding: 5px 0; font-size: 14px; white-space: nowrap; }
.inv-ledger .l { text-align: right; padding-right: 20px; color: var(--muted); }
.inv-ledger .d { text-align: right; padding-right: 20px; color: var(--muted); }
.inv-ledger .v { text-align: right; font-variant-numeric: tabular-nums; min-width: 110px; }
.inv-ledger .strong .l, .inv-ledger .strong .v { font-weight: 700; color: var(--ink); }
.inv-ledger .final .l { color: var(--muted); }
.inv-ledger .final .v { font-weight: 700; color: var(--ink); }
.inv-ledger .rule td { border-top: 1px solid var(--line); padding: 0; line-height: 0; height: 8px; }
.inv-ledger .hdr td { text-align: center; color: var(--brand); font-size: 13px; padding-top: 8px; }

/* ── Customs clearance (Slice C) ───────────────────────────────────────────── */
.doc-row { padding: .75rem 0; border-bottom: 1px solid var(--line); }
.doc-row:last-child { border-bottom: 0; }
.doc-row__head { display: flex; align-items: center; gap: .75rem; margin-bottom: .35rem; }
.doc-row__file { display: flex; align-items: center; gap: .75rem; font-size: 13px; margin: .25rem 0; }
.doc-row__upload { display: flex; gap: .5rem; align-items: center; margin-top: .35rem; max-width: 32rem; }
.instruction-sheet h2 { font-size: 18px; margin: 0 0 .25rem; }
.instruction-sheet h3 { font-size: 14px; margin: 1.25rem 0 .5rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.check-list { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: .35rem; }
.is-derived { background: var(--canvas) !important; cursor: not-allowed; opacity: .85; }
.sig-readout { padding: .5rem .75rem; border: 1px solid var(--line); border-radius: 8px; background: var(--canvas); }
.sig-readout__name { display: block; margin: 0; font-weight: 600; color: var(--ink); }
.sig-readout__date { display: block; margin: 0; color: var(--muted); }
.signature-block { display: flex; gap: 4rem; margin-top: 2.5rem; }
.sig-line { display: inline-block; width: 12rem; border-bottom: 1px solid var(--ink); height: 1.5rem; }
@media print {
  .no-print, .sidebar, .topbar, .shell__rail { display: none !important; }
  .shell, .shell__main, .shell__content, .shell__canvas { display: block !important; margin: 0 !important; }
  .card { box-shadow: none !important; border: 0 !important; }
}

/* ===== Select2 ↔ Bootstrap 5 / brand bridge ===============================
   Make the app-wide Select2 controls match .form-select (size, border, radius)
   and follow light/dark via Bootstrap's --bs-* variables (with app-token fallbacks). */
.select2-container { width: 100% !important; }
.select2-container--default .select2-selection--single {
  /* Match .form-control EXACTLY. The height formula is Bootstrap's own, but `em` resolves against
     this element's font — which inherits the page's 14px, not the control's 1rem — so without the
     font-size every Select2 in the app came out 3px shorter than the input beside it, and its text
     a size smaller. Set the font first, and the same calc lands on the same height. */
  font-size: 1rem;
  height: calc(1.5em + .75rem + 2px);
  padding: .375rem 1.75rem .375rem .75rem;
  border: 1px solid var(--bs-border-color, var(--line));
  border-radius: var(--bs-border-radius, .375rem);
  background: var(--bs-body-bg, var(--card));
  display: flex; align-items: center;
}
/* The small size, mirroring .form-control-sm — select2-init tags the container when the source
   select carried `form-select-sm`. Same reasoning as the base rule: set the font first, or `em`
   resolves against the inherited page size and the height comes out wrong. */
.select2-container.select2--sm .select2-selection--single {
  font-size: .875rem;
  height: calc(1.5em + .5rem + 2px);
  padding: .25rem 1.75rem .25rem .5rem;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
  color: var(--bs-body-color, var(--ink)); padding: 0; line-height: 1.5;
}
.select2-container--default .select2-selection--single .select2-selection__placeholder { color: var(--muted); }
.select2-container--default .select2-selection--single .select2-selection__arrow { height: 100%; top: 0; right: 6px; }
.select2-container--default.select2-container--focus .select2-selection--single,
.select2-container--default.select2-container--open .select2-selection--single {
  border-color: var(--brand);
  box-shadow: 0 0 0 .25rem var(--brand-tint, rgba(28,143,191,.25));
  outline: 0;
}
.select2-dropdown {
  background: var(--bs-body-bg, var(--card));
  border-color: var(--bs-border-color, var(--line));
  color: var(--bs-body-color, var(--ink));
  z-index: 1080;
}
.select2-container--default .select2-results__option { color: var(--bs-body-color, var(--ink)); }
.select2-container--default .select2-results__option--highlighted[aria-selected],
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
  background: var(--brand); color: #fff;
}
.select2-container--default .select2-results__option[aria-selected=true],
.select2-container--default .select2-results__option--selected {
  background: var(--brand-tint, rgba(28,143,191,.16)); color: var(--ink);
}
.select2-container--default .select2-results__group {
  color: var(--muted); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
}
.select2-search--dropdown .select2-search__field {
  background: var(--bs-body-bg, var(--card)); color: var(--bs-body-color, var(--ink));
  border: 1px solid var(--bs-border-color, var(--line)); border-radius: var(--bs-border-radius, .375rem);
}

/* ===== Responsive — small screens / mobile off-canvas sidebar ============= */
.sidebar-backdrop { display: none; }

@media (max-width: 768px) {
  /* Single-column shell; the sidebar overlays as an off-canvas drawer. */
  .shell, .shell.is-collapsed { grid-template-columns: 1fr; }
  .sidebar {
    position: fixed; top: 0; left: 0; z-index: 300;
    width: min(84vw, var(--sidebar-w)); height: 100vh;
    transform: translateX(-100%); transition: transform .22s ease;
  }
  .shell.is-mobile-open .sidebar { transform: translateX(0); box-shadow: 0 0 40px rgba(0,0,0,.5); }

  /* Neutralise any leftover desktop icon-rail collapse on mobile — always the full drawer. */
  .shell.is-collapsed .sidebar__brand .logo { display: block; }
  .shell.is-collapsed .sidebar__brand .mark { display: none; }
  .shell.is-collapsed .nav-item, .shell.is-collapsed .nav-group > summary { justify-content: flex-start; padding: 0 12px; }
  .shell.is-collapsed .nav-item__label, .shell.is-collapsed .nav-item__chev { display: flex; }
  .shell.is-collapsed .nav-section__head { display: flex; }
  .shell.is-collapsed .nav-section__label { color: #647C95; height: auto; overflow: visible; }
  .shell.is-collapsed .nav-group__items { position: static; min-width: 0; padding: 2px 0 6px; background: none; border: 0; box-shadow: none; }
  .shell.is-collapsed .nav-group:not([open]) > .nav-group__items { display: none; }
  .shell.is-collapsed .nav-group[open] > .nav-group__items { display: flex; }
  .shell.is-collapsed .nav-group__title { display: none; }
  .shell.is-collapsed .nav-subitem { padding: 0 12px 0 36px; }

  /* Backdrop behind the open drawer. */
  .sidebar-backdrop {
    display: block; position: fixed; inset: 0; z-index: 290;
    background: rgba(0,0,0,.45); opacity: 0; pointer-events: none; transition: opacity .2s ease;
  }
  .shell.is-mobile-open .sidebar-backdrop { opacity: 1; pointer-events: auto; }

  .shell__content { padding: 14px; gap: 14px; }
  .page-head { gap: 10px; }
  .page-head h1 { font-size: 20px; }
  h1 { font-size: 22px; }

  /* (Wide-table horizontal scroll is now global — see the .card > .table / .dt-container
     rule near the .table base styles — so it also covers tablet widths, not just phones.) */

  /* Compact top bar; drop the keyboard hint + secondary icons. */
  .topbar { gap: 10px; padding: 0 12px; }
  .topbar__kbd { display: none; }
  .topbar__actions { gap: 2px; }
}

@media (max-width: 520px) {
  .user-chip__meta { display: none; }
  .form-actions .btn { flex: 1 1 auto; }
}

/* ── Leave calendar ─────────────────────────────────────────────────── */
.cal-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.cal-nav { display: flex; align-items: center; gap: 8px; }
.cal-month { font-size: 18px; margin: 0; min-width: 9.5em; text-align: center; }

.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; background: var(--bs-border-color, var(--line)); border: 1px solid var(--bs-border-color, var(--line)); border-radius: 10px; overflow: hidden; }
.cal-dow { background: var(--bs-tertiary-bg, var(--pale)); padding: 8px 6px; font-size: 12px; font-weight: 600; text-align: center; color: var(--bs-secondary-color, var(--muted)); text-transform: uppercase; letter-spacing: .04em; }
.cal-cell { background: var(--bs-body-bg, var(--card)); min-height: 104px; padding: 6px; display: flex; flex-direction: column; gap: 4px; }
.cal-cell.is-outside { background: var(--bs-tertiary-bg, var(--pale)); }
.cal-cell.is-outside .cal-daynum { opacity: .45; }
.cal-cell.is-weekend:not(.is-outside) { background: color-mix(in srgb, var(--bs-tertiary-bg, var(--pale)) 55%, transparent); }
.cal-cell.is-today { box-shadow: inset 0 0 0 2px var(--bs-primary, var(--brand)); }
.cal-daynum { font-size: 12px; font-weight: 600; color: var(--bs-secondary-color, var(--muted)); }
.cal-cell.is-today .cal-daynum { color: var(--bs-primary, var(--brand)); }
.cal-events { display: flex; flex-direction: column; gap: 3px; }
.cal-event { font-size: 11px; line-height: 1.25; padding: 2px 6px; border-radius: 5px; overflow: hidden; cursor: default; }
.cal-event__name { display: block; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-event__type { display: block; opacity: .85; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-legend { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }

@media (max-width: 768px) {
  .cal-cell { min-height: 72px; }
  .cal-event__type { display: none; }
}

/* ── Leave rules ────────────────────────────────────────────────────── */
.rules-types { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 14px; }
.rule-card { border: 1px solid var(--bs-border-color, var(--line)); border-radius: 10px; padding: 14px; background: var(--bs-body-bg, var(--card)); }
.rule-card__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.rule-card__head .badge { margin-left: 6px; }
.rule-facts { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 14px; margin: 0; }
.rule-facts > div { display: flex; flex-direction: column; }
.rule-facts dt { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--bs-secondary-color, var(--muted)); }
.rule-facts dd { margin: 0; font-size: 13px; font-weight: 500; }
.rule-edit { margin-top: 12px; }

/* Leave policy: a 3-column layout (Setting / Value / Save). Every row + the header share one
   column template, so the columns line up; contents are left-aligned. */
.settings-grid__head,
.settings-grid__row { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) 96px; align-items: center; column-gap: 16px; margin: 0; }
.settings-grid__head { padding: 0 0 8px; font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: var(--bs-secondary-color, var(--muted)); border-bottom: 1px solid var(--bs-border-color, var(--line)); }
.settings-grid__row { padding: 12px 0; border-bottom: 1px solid var(--bs-border-color, var(--line)); }
.settings-grid__row:last-child { border-bottom: none; }
.settings-grid__label { font-weight: 600; text-align: left; }
.settings-grid__value { text-align: left; }
.settings-grid__value .form-control,
.settings-grid__value .form-select { width: 100%; }
.settings-grid__row .btn { width: 100%; }

@media (max-width: 640px) {
  .settings-grid__head { display: none; }
  .settings-grid__row { grid-template-columns: 1fr 96px; row-gap: 8px; padding: 14px 0; }
  .settings-grid__label { grid-column: 1 / -1; }
}

/* Native <dialog> overlay for the leave-type edit form. */
.rule-modal { border: none; border-radius: 12px; padding: 0; width: min(680px, calc(100vw - 32px)); background: var(--bs-body-bg, var(--card)); color: var(--bs-body-color, var(--ink)); box-shadow: 0 24px 64px rgba(0, 0, 0, .35); }
.rule-modal::backdrop { background: rgba(0, 0, 0, .5); }
.rule-modal__panel { padding: 20px; }
.rule-modal__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid var(--bs-border-color, var(--line)); }
.rule-modal__head strong { font-size: 16px; }
.rule-modal__actions { grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: 10px; }

/* Internal-only panel (e.g. SO "sourced from cargo") — staff-facing, never customer output. */
.card--internal { border-left: 3px solid var(--brand, #1C8FBF); }
.card--internal .card-head { display: flex; align-items: center; gap: 10px; }

/* ── Cargo status-workflow explainer ─────────────────────────────────────── */
.workflow-link { font-size: 12.5px; vertical-align: baseline; }
/* Status cell: pill + the small "?" workflow trigger */
.wf-status-cell { white-space: nowrap; }
/* Padlocked cargo action (user lacks cargo-edit rights): muted, non-actioning — a permission toast on click. */
.wf-locked { opacity: .6; cursor: not-allowed; }
.wf-locked .ico { width: 13px; height: 13px; }
.wf-info { margin-left: 6px; width: 18px; height: 18px; padding: 0; border-radius: 50%;
    border: 1px solid var(--bs-border-color, var(--line)); background: transparent;
    color: var(--bs-secondary-color, var(--muted)); font-size: 11px; font-weight: 700; line-height: 1;
    cursor: pointer; vertical-align: middle; }
.wf-info:hover { color: var(--brand); border-color: var(--brand); }
.wf-customs { text-decoration: none; }
.wf-actions { white-space: nowrap; }
.wf-actions form { vertical-align: middle; }
.wf-actions form + form, .wf-actions form + button, .wf-actions button + form { margin-left: 6px; }

/* "Waiting on" — the sale-readiness validations still outstanding on a cargo (shown under its status) */
.wf-waiting { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 6px; white-space: normal; max-width: 260px; }
.wf-waiting__lead { display: inline-flex; align-items: center; gap: 3px; font-size: 11px; font-weight: 600; color: var(--warn, #b26a00); }
.wf-waiting__lead .ico { width: 13px; height: 13px; }
.wf-waiting__chip { font-size: 11px; line-height: 1; padding: 3px 7px; border-radius: 999px;
    background: color-mix(in srgb, var(--warn, #b26a00) 14%, transparent);
    color: var(--warn, #b26a00); border: 1px solid color-mix(in srgb, var(--warn, #b26a00) 30%, transparent); }

/* The vertical stepper inside the modal */
.workflow-modal { width: min(560px, calc(100vw - 32px)); }
.wf-steps { list-style: none; margin: 14px 0 0; padding: 0; position: relative; }
.wf-steps::before { content: ''; position: absolute; left: 13px; top: 12px; bottom: 40px; width: 2px;
    background: var(--bs-border-color, var(--line)); }
.wf-step { position: relative; padding: 7px 10px 7px 36px; border-radius: 8px;
    display: flex; flex-direction: column; gap: 1px; }
.wf-step__dot { position: absolute; left: 8px; top: 11px; width: 12px; height: 12px; border-radius: 50%;
    background: var(--bs-body-bg, var(--card)); border: 2px solid var(--bs-border-color, var(--line)); }
.wf-step__label { font-weight: 600; font-size: 13.5px; }
.wf-step__gate { font-size: 11.5px; color: var(--bs-secondary-color, var(--muted)); }
.wf-step--gate .wf-step__gate { color: #0A6E96; font-weight: 600; }
.wf-step--gate .wf-step__dot { border-color: var(--brand); }
.wf-step--cancel { margin-top: 14px; }
.wf-step--cancel .wf-step__dot { border-color: #C0504A; }
.wf-step--cancel .wf-step__label { color: #C0504A; }
/* Contextual highlight ("you are here" + neighbours) */
.wf-step.is-current { background: rgba(28, 143, 191, .12); }
.wf-step.is-current .wf-step__dot { background: var(--brand); border-color: var(--brand);
    box-shadow: 0 0 0 3px rgba(28, 143, 191, .22); }
.wf-step.is-current .wf-step__label { color: var(--brand); }
.wf-step.is-next .wf-step__dot, .wf-step.is-prev .wf-step__dot { border-color: var(--brand); }
.wf-note { margin-top: 16px; font-size: 12px; display: flex; align-items: center; gap: 6px;
    padding-top: 12px; border-top: 1px solid var(--bs-border-color, var(--line)); }
.wf-note .ico { width: 15px; height: 15px; flex: none; }

/* Inventory — storage tank cards (§11.2) */
.tank-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 12px; }
.tank-card { border: 1px solid var(--bs-border-color, var(--line)); border-radius: 10px; background: var(--bs-body-bg, var(--card)); }
.tank-card > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 10px;
    flex-wrap: wrap; padding: 12px 14px; }
.tank-card > summary::-webkit-details-marker { display: none; }
.tank-card__no { font-weight: 600; font-variant-numeric: tabular-nums; }
.tank-card__cap { margin-left: auto; font-size: 12px; }
.tank-edit { padding: 4px 14px 14px; border-top: 1px solid var(--bs-border-color, var(--line)); margin-top: 4px; }
.add-tank > summary { display: inline-flex; width: auto; list-style: none; cursor: pointer; }
.add-tank > summary::-webkit-details-marker { display: none; }

/* Inventory — Stock Position KPI strip (§11.2) */
.stock-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 16px; }
.stock-kpi { display: flex; flex-direction: column; gap: 4px; }
.stock-kpi > strong { font-size: 1.6rem; font-variant-numeric: tabular-nums; line-height: 1.1; }
.stock-kpi > strong.ok { color: var(--success-ink, #1c7c54); }
.stock-kpi__u { font-size: .9rem; font-weight: 500; color: var(--muted); }

/* CRM — pipeline kanban board (§17) */
.pipeline-board { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 8px; align-items: flex-start; }
.pipeline-col { flex: 0 0 260px; background: var(--bs-tertiary-bg, #f1f3f7); border-radius: 10px; display: flex; flex-direction: column; }
[data-bs-theme="dark"] .pipeline-col { background: rgba(255,255,255,.04); }
.pipeline-col.is-over { outline: 2px dashed var(--brand); outline-offset: -2px; }
.pipeline-col__head { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; padding: 10px 12px; border-bottom: 1px solid var(--bs-border-color, var(--line)); }
.pipeline-col__name { font-weight: 600; font-size: 13px; }
.pipeline-col__meta { font-size: 11px; color: var(--muted); white-space: nowrap; }
.pipeline-col__body { padding: 8px; display: flex; flex-direction: column; gap: 8px; min-height: 60px; }
.pipeline-col__empty { text-align: center; margin: 8px 0; }
.pipeline-card { display: block; background: var(--bs-body-bg, var(--card)); border: 1px solid var(--bs-border-color, var(--line));
    border-radius: 8px; padding: 10px; text-decoration: none; color: inherit; cursor: grab; box-shadow: 0 1px 2px rgba(0,0,0,.04); }
.pipeline-card:hover { border-color: var(--brand); }
.pipeline-card.is-dragging { opacity: .5; }
.pipeline-card__title { font-weight: 600; font-size: 13px; line-height: 1.25; }
.pipeline-card__sub { font-size: 12px; margin-top: 2px; }
.pipeline-card__row { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; font-size: 12px; margin-top: 6px; }
.pipeline-card__val { font-weight: 600; font-variant-numeric: tabular-nums; }
.pipeline-card__due--over { color: var(--danger-ink, #b5453b); font-weight: 600; }
.pipeline-card__tag { margin-top: 6px; font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }

/* --- Daily BFP: press-release contribution cards -------------------------------------------
   Five per-grade figures inside the press-release parent card. Auto-fit so they sit one row on
   desktop and wrap cleanly on narrow screens; the left rule carries the up/down signal alongside
   the arrow + wording (never colour alone). */
.pr-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; }
.pr-card { display: flex; flex-direction: column; gap: 4px; padding: 14px; background: var(--canvas, var(--card)); border: 1px solid var(--line); border-left: 3px solid var(--line); border-radius: var(--radius-control); }
.pr-card--increase { border-left-color: var(--danger, #b5453b); }
.pr-card--decrease { border-left-color: var(--success, #2f8f5b); }
.pr-card__title { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.pr-card__value { font-size: 20px; font-weight: 600; font-variant-numeric: tabular-nums; }
.pr-card__delta { font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
.pr-card__prev  { font-size: 11px; font-variant-numeric: tabular-nums; }

/* --- Read-only impersonation banner ---------------------------------------------------------
   Sits above the top bar on every in-app page. Amber (warning), not red: this is a deliberate
   admin state, not an error — but it must be impossible to miss or mistake for normal browsing. */
.impersonation-bar { display: flex; align-items: center; gap: 10px; padding: 8px 20px; background: var(--warning, #E2A02E); color: #2b2000; font-size: 13px; }
.impersonation-bar .ico { width: 16px; height: 16px; flex: 0 0 auto; }
.impersonation-bar__text { flex: 1 1 auto; }
.impersonation-bar__email { opacity: .75; }
.impersonation-bar form { margin: 0; }

/* Chart card head carrying more than one control group (e.g. the BFP trend's product + day-range
   toggles) — wrap onto its own line rather than crushing the heading on narrow screens. */
.card-head--wrap { flex-wrap: wrap; gap: 10px; }
.chart-toggles { display: flex; flex-wrap: wrap; gap: 8px; margin-left: auto; }
.pr-card__sell { font-size: 11px; padding-top: 6px; border-top: 1px solid var(--line); margin-top: 2px; font-variant-numeric: tabular-nums; }
/* Latest-change cards reuse the press-release card shell; these two tones mirror the direction
   badges they replaced (decrease = good/green, increase = bad/red), alongside the ▼/▲ + wording. */
.pr-card--decrease { border-left-color: var(--success, #1FA06B); }
.pr-card--increase { border-left-color: var(--danger, #DF534B); }
/* A long status badge in a card head must be able to wrap — otherwise its fixed single line is
   wider than a phone viewport and pushes the whole page into horizontal scroll. */
.badge--wrap { white-space: normal; text-align: left; }

/* ---- Guided tour (driver.js popovers) -------------------------------------------------
   driver.js cannot read CSS variables itself, so the popover carries the `umt-tour` class
   (set once in assets/tour.js) and is themed here from the design tokens. Light AND dark:
   the tokens invert, so the same rules serve both. See GUIDED_TOUR_SPEC. */
.driver-popover.umt-tour {
    background: var(--card);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    box-shadow: 0 18px 44px rgba(10, 26, 47, .22);
    max-width: 340px;
    font-family: var(--font-body);
}
.driver-popover.umt-tour .driver-popover-title {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 700;
    color: var(--ink);
}
.driver-popover.umt-tour .driver-popover-description { color: var(--muted); font-size: .875rem; line-height: 1.55; }
/* The popover arrow is a bordered triangle per side — recolour all four to the card surface,
   or the tooltip appears to float away from a dark-mode card. */
.driver-popover.umt-tour .driver-popover-arrow-side-top { border-top-color: var(--card); }
.driver-popover.umt-tour .driver-popover-arrow-side-bottom { border-bottom-color: var(--card); }
.driver-popover.umt-tour .driver-popover-arrow-side-left { border-left-color: var(--card); }
.driver-popover.umt-tour .driver-popover-arrow-side-right { border-right-color: var(--card); }
.driver-popover.umt-tour .driver-popover-progress-text { color: var(--muted); font-size: .78rem; }
.driver-popover.umt-tour .driver-popover-close-btn { color: var(--muted); }
.driver-popover.umt-tour .driver-popover-close-btn:hover { color: var(--ink); }
/* Buttons: Bootstrap owns button styling everywhere else in the app, but driver.js renders its
   own <button>s, so the app's look is reproduced here rather than fought with. */
.driver-popover.umt-tour .driver-popover-footer button {
    text-shadow: none;
    border-radius: var(--radius-control);
    padding: .3rem .75rem;
    font-size: .82rem;
    font-weight: 600;
    border: 1px solid var(--line);
    background: transparent;
    color: var(--ink);
}
.driver-popover.umt-tour .driver-popover-footer button:hover { background: rgba(28, 143, 191, .10); }
.driver-popover.umt-tour .driver-popover-footer .driver-popover-next-btn {
    background: var(--brand);
    border-color: var(--brand);
    color: #fff;
}
.driver-popover.umt-tour .driver-popover-footer .driver-popover-next-btn:hover { filter: brightness(1.06); }
/* Honour the OS setting — the engine also disables its own animation (assets/tour.js). */
@media (prefers-reduced-motion: reduce) {
    .driver-popover.umt-tour, .driver-active-element { transition: none !important; }
}

/* ---- Getting started hub (guided tour, GUIDED_TOUR_SPEC §10.2) ------------------------ */
.gs-progress { display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.gs-progress__count { margin: 0; font-size: 15px; }
.gs-progress__count strong { font-family: var(--font-display); font-size: 20px; color: var(--brand); }
.gs-bar { flex: 1 1 220px; max-width: 380px; height: 8px; border-radius: var(--radius-pill); background: var(--line); overflow: hidden; }
.gs-bar__fill { display: block; height: 100%; background: var(--brand); border-radius: var(--radius-pill); transition: width .3s ease; }
@media (prefers-reduced-motion: reduce) { .gs-bar__fill { transition: none; } }

.gs-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; margin-top: 16px; }
.gs-card { display: flex; flex-direction: column; gap: 8px; }
.gs-card__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.gs-card__title { font-family: var(--font-display); font-size: 16px; margin: 0; color: var(--ink); }
.gs-card__body { margin: 0; font-size: 13.5px; color: var(--muted); line-height: 1.55; }
.gs-card__meta { margin: 0; font-size: 12px; }
/* The written guide behind a walkthrough. Sits under the actions, quieter than them: it is the
   thing you reach for after the tour, not instead of it. */
.gs-card__guide { display: flex; align-items: center; gap: .4rem; margin: .65rem 0 0; font-size: 12px; }
.gs-card__guide .ico { width: 14px; height: 14px; flex: 0 0 auto; }
/* Actions pinned to the bottom so cards of differing text length still line up. */
.gs-card__actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: auto; padding-top: 8px; }
/* A finished goal recedes; one in progress is the thing to come back to, so it gets the accent. */
.gs-card--completed { opacity: .78; }
.gs-card--in_progress { border-left: 3px solid var(--brand); }
.gs-card--skipped { opacity: .62; }
.gs-foot { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 18px; }

/* Base-currency control on Administration → Companies. It sits in the page head beside "Add
   company" because the currency spans every company in the list rather than belonging to one. */
.currency-bar { display: flex; align-items: flex-end; gap: .75rem; flex-wrap: wrap; margin-top: .75rem; }
.currency-bar .form-select { min-width: 20rem; }
.currency-note { font-size: .8125rem; color: var(--muted); max-width: 34rem; }
.currency-note .form-check { margin-top: .25rem; }
@media (max-width: 768px) { .currency-bar .form-select { min-width: 0; width: 100%; } }

/* Ad-hoc invoice editor: the issuing company's letterhead preview under the company picker.
   It updates live from the dropdown, so it needs to sit where the static block used to. */
.inv-company__profile { margin-top: .5rem; font-size: .8125rem; line-height: 1.45; }

/* Per-user permission overrides (/users/{id}/permissions).
   Each table row carries its own one-capability form: level + reason + Save on a single line,
   so a change reads as one deliberate act rather than part of a bulk grid edit. */
.perm-row-form {
    display: flex;
    gap: .5rem;
    align-items: center;
    flex-wrap: wrap;
}
.perm-row-form .form-select { width: auto; min-width: 11rem; }
.perm-row-form .form-control { width: auto; min-width: 14rem; flex: 1 1 14rem; }

/* ---------------------------------------------------------------------------
   Detail grid — several small read-only field groups side by side inside one card.
   Used by the sales order's "Order details" (Pricing / Sales assessment / Follow-up /
   Approval): each group is only three or four rows, so stacking them left most of the
   card empty and pushed everything below it off the first screen. auto-fit means the
   browser decides how many fit — four across on a wide monitor, two on a laptop, one
   on a phone — without a breakpoint per layout.
   --------------------------------------------------------------------------- */
.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13.5rem, 1fr));
  gap: 14px;
}
.detail-card {
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  padding: 12px 14px;
  background: var(--bg);
  min-width: 0;
}
.detail-card__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
  margin: 0 0 6px;
}
/* .totals is right-aligned and capped at 20rem for an invoice ledger; inside a detail
   card it is a plain label/value list and must fill its column. */
.detail-card .totals { max-width: none; margin-left: 0; }
.detail-card .totals .row { align-items: baseline; gap: 12px; }
.detail-card .totals .row span:last-child { text-align: right; word-break: break-word; }

/* ---------------------------------------------------------------------------
   Editable line-entry rows (the quotation editor).

   The first cell stacks a Product + Terminal pair above a description input, so it is far taller
   than the single-control cells beside it. Under the default TOP alignment the Rate and Qty inputs
   sat 62px above the description — level with the labels rather than with any input, so nothing on
   the row read as one line.

   Bottom alignment puts the row's inputs on a single line. Scoped to this table on purpose: the
   read-only document tables share `.inv-lines` and must keep top alignment, where an amount belongs
   against the FIRST line of a multi-line description, not the last.
   --------------------------------------------------------------------------- */
.inv-lines--entry td { vertical-align: bottom; }
/* The line total is TEXT, not a control, so it has no box to bottom-align — a bare text node's
   baseline lands wherever its line box happens to fall. Give it one the same height as a
   .form-control-sm (Bootstrap's own formula: line-height + padding + borders) and centre the figure
   in it, exactly as an input centres its own text. The baselines then match by construction, rather
   than by a magic offset that the next control-size change would silently break. */
.inv-lines--entry .line-total-value {
  display: inline-flex;
  align-items: center;
  height: calc(1.5em + .5rem + 2px);
}
/* Even gap between the selects above and the line of inputs below. */
.inv-lines--entry td > .form-grid { margin-bottom: 8px; }

/* ── Wizard step indicator ──────────────────────────────────────────────────────────────────────
   Two steps, shown on both, so a user who lands on step 2 from a link knows there was a step 1 and
   that they are near the end — a form that appears out of nowhere reads as an error. */
.wizard-steps { display: flex; gap: 10px; list-style: none; margin: 0 0 20px; padding: 0; flex-wrap: wrap; }
.wizard-steps li {
    display: flex; align-items: center; gap: 8px;
    padding: 8px 16px 8px 10px; border: 1px solid var(--line); border-radius: 999px;
    font-size: 13px; color: var(--muted); background: var(--card);
}
.wizard-steps__n {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px; border-radius: 50%; flex: 0 0 auto;
    background: var(--line); color: var(--muted); font-size: 12px; font-weight: 600;
}
.wizard-steps__n .ico { width: 13px; height: 13px; }
.wizard-steps .is-current { border-color: var(--brand); color: var(--ink); font-weight: 600; }
.wizard-steps .is-current .wizard-steps__n { background: var(--brand); color: #fff; }
.wizard-steps .is-done { border-color: var(--success); color: var(--success-ink); }
.wizard-steps .is-done .wizard-steps__n { background: var(--success); color: #fff; }

/* The footnote under the gap cards. Sits with the row rather than inside a card, so it needs its
   own breathing room and a width that stays readable — a full-bleed line of small grey text across
   a wide monitor is a line nobody finishes. */
.gaps-note { max-width: 78ch; margin: -12px 0 28px; font-size: 13px; line-height: 1.6; }
