/* =====================================================================
   SOP Central Repository - application styles
   Mobile-first. Data tables collapse to cards below 768px.
   ===================================================================== */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    font-family: var(--font);
    font-size: var(--text-md);
    line-height: 1.4;
    letter-spacing: -.005em;
    color: var(--ink-700);
    background: var(--surface-sunken);
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}
* { -webkit-tap-highlight-color: transparent; }

/* Numbers that sit in a column must not jitter as they change. */
.mono, .kpi__value, .statline dd, .table__num { font-variant-numeric: tabular-nums; }

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: #c8d3cd; border-radius: 8px; }

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

h1, h2, h3, h4 { margin: 0; font-weight: 650; color: var(--ink-900); line-height: 1.28; letter-spacing: -.02em; }
p { margin: 0 0 var(--sp-3); }
a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--accent-700); text-decoration: underline; }
img { max-width: 100%; height: auto; }
hr { border: 0; border-top: 1px solid var(--ink-100); margin: var(--sp-5) 0; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-sm); }

.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------------------------------------------------------------- shell */

.shell { display: flex; min-height: 100vh; }

.sidebar {
    position: fixed; inset: 0 auto 0 0;
    width: var(--sidebar-w);
    background: linear-gradient(180deg, var(--brand-sidebar) 0%, var(--brand-900) 100%);
    color: rgba(255,255,255,.80);
    display: flex; flex-direction: column;
    z-index: 60;
    transform: translateX(-100%);
    transition: transform var(--t);
}
.sidebar.is-open { transform: translateX(0); box-shadow: var(--sh-lg); }

/* A white plate behind the mark: the logo is dark green on transparent and
   would disappear into the panel. The plate stays square - the lockup carries
   its own shape. */
.sidebar__brand {
    display: flex; align-items: center; justify-content: center;
    height: var(--topbar-h); flex: 0 0 var(--topbar-h);
    padding: 0 var(--sp-4);
    background: #fff;
    border-bottom: 1px solid var(--line);
}
/* 26px, not 38: the brand bar is exactly --topbar-h tall, so at 46px a 38px
   logo leaves 4px of air and reads as jammed in. The radius stays 0 - the
   lockup carries its own shape. */
.sidebar__brand img { height: 26px; width: auto; max-width: 100%; display: block; border-radius: 0; }

.sidebar__nav { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 7px 7px 10px; }
.sidebar__group { margin-top: var(--sp-3); }
.sidebar__group:first-child { margin-top: 0; }
.sidebar__label {
    padding: 9px 6px 3px;
    font-size: .5625rem; font-weight: 700; letter-spacing: .14em;
    text-transform: uppercase; color: rgba(255,255,255,.40);
}

/* A nav row is --row tall, so the nine items clear the fold without scrolling
   even on a laptop. */
.navlink {
    display: flex; align-items: center; gap: 9px;
    height: var(--row); padding: 0 8px; margin-bottom: 1px;
    border-radius: var(--r-sm);
    color: rgba(255,255,255,.80); font-size: .78rem; font-weight: 500;
    transition: background var(--t), color var(--t);
}
.navlink:hover { background: rgba(55,179,75,.16); color: #fff; text-decoration: none; }
/* The active pill is lit from within: a gradient plus an inset top highlight,
   so it reads as a raised surface rather than a flat block of colour. */
.navlink.is-active {
    background: linear-gradient(135deg, var(--accent) 0%, #22A03D 100%);
    color: #fff; font-weight: 600;
    box-shadow: 0 3px 8px -4px rgba(55,179,75,.75), inset 0 1px 0 rgba(255,255,255,.20);
}
.navlink svg { flex: 0 0 15px; width: 15px; height: 15px; opacity: .9; }
.navlink__badge {
    margin-left: auto; background: rgba(255,255,255,.18); color: #fff;
    font-size: .625rem; font-weight: 700; padding: 0 6px; line-height: 15px;
    border-radius: var(--r-full);
}
.navlink.is-active .navlink__badge { background: rgba(0,0,0,.22); }

/* Pinned outside the scroll area, so sign-out is reachable at any nav length.
   flex: 0 0 auto keeps it from shrinking when the nav overflows. */
.sidebar__foot {
    flex: 0 0 auto; padding: 6px 7px 7px;
    border-top: 1px solid rgba(255,255,255,.10);
    background: rgba(0,0,0,.16);
}
.sidebar__foot form { margin: 0; }
.sidebar__org {
    margin: 8px 0 0; padding: 0 var(--sp-2);
    font-size: var(--text-xs); line-height: 1.5; color: rgba(255,255,255,.45);
}

/* A button, not a link: signing out is a POST. It has to look identical to the
   nav links above it, so the reset is explicit rather than inherited. */
.navlink--out {
    width: 100%; border: 0; background: transparent;
    font-family: inherit; font-size: .78rem; font-weight: 550;
    text-align: left; cursor: pointer;
    color: #FFC9C9;
}
.navlink--out:hover { background: rgba(220,53,69,.22); color: #fff; }
.navlink--out:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* The nav is the only part that scrolls. A dark, thin thumb, because the page
   scrollbar rule is tuned for a light surface and reads as a bright stripe here. */
.sidebar__nav { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.22) transparent; }
.sidebar__nav::-webkit-scrollbar { width: 6px; }
.sidebar__nav::-webkit-scrollbar-track { background: transparent; }
.sidebar__nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,.20); border-radius: 6px; }
.sidebar__nav::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.34); }

.scrim {
    position: fixed; inset: 0; background: rgba(15,23,42,.5); z-index: 55;
    opacity: 0; pointer-events: none; transition: opacity var(--t);
}
.scrim.is-open { opacity: 1; pointer-events: auto; }

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

/* Translucent and blurred, so content scrolling under it stays legible without
   a hard shadow line. Falls back to solid where backdrop-filter is absent. */
.topbar {
    position: sticky; top: 0; z-index: 40;
    height: var(--topbar-h);
    background: rgba(255,255,255,.86);
    backdrop-filter: blur(10px) saturate(150%);
    -webkit-backdrop-filter: blur(10px) saturate(150%);
    border-bottom: 1px solid var(--line);
    display: flex; align-items: center; gap: var(--sp-3);
    padding: 0 var(--sp-5);
}
@supports not (backdrop-filter: blur(2px)) { .topbar { background: var(--surface); } }

.iconbtn {
    display: grid; place-items: center;
    width: var(--ctl); height: var(--ctl);
    border: 0; background: transparent; border-radius: var(--r-sm);
    cursor: pointer; color: var(--ink-600); position: relative;
    transition: background var(--t);
}
.iconbtn { border: 1px solid transparent; }
.iconbtn:hover { background: var(--accent-100); color: var(--brand); border-color: #CDEBD6; }
.iconbtn__dot {
    position: absolute; top: 1px; right: 1px;
    min-width: 14px; height: 14px; padding: 0 3px;
    background: var(--accent); color: #fff; border-radius: var(--r-full);
    font-size: .5625rem; font-weight: 700; display: grid; place-items: center;
}

.search { flex: 1; max-width: 380px; position: relative; display: none; }
.search input {
    width: 100%; height: var(--ctl); padding: 0 var(--sp-3) 0 30px;
    border: 1px solid var(--ink-200); border-radius: var(--r-sm);
    font-size: var(--text-md); font-family: inherit; background: var(--ink-050);
}
.search input:focus { background: #fff; border-color: var(--brand); outline: none; box-shadow: 0 0 0 3px var(--brand-100); }
.search svg { position: absolute; left: 9px; top: 6px; width: 15px; height: 15px; color: var(--ink-400); }

.spacer { flex: 1; }

/* mode pill */
.modepill {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 9px; border-radius: var(--r-full);
    font-size: .5625rem; font-weight: 700; letter-spacing: .09em;
}
.modepill--test { background: var(--accent); color: #fff; }
.modepill--live { background: var(--success-bg); color: var(--success); }
.modepill::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; }

/* user menu */
.usermenu { position: relative; }
.usermenu__btn {
    display: flex; align-items: center; gap: var(--sp-2);
    padding: var(--sp-1) var(--sp-2); background: transparent; border: 0;
    border-radius: var(--r-sm); cursor: pointer; font-family: inherit;
    font-size: var(--text-md); color: var(--ink-800);
}
.usermenu__btn:hover { background: var(--ink-050); }
.avatar {
    width: 26px; height: 26px; flex: 0 0 26px; border-radius: 50%;
    background: linear-gradient(145deg, #E8F6EC, #D3EEDB);
    color: var(--brand); font-weight: 750;
    display: grid; place-items: center; font-size: .625rem;
    box-shadow: inset 0 0 0 1px rgba(0,121,63,.10);
}
.usermenu__name { display: none; text-align: left; line-height: 1.2; }
.usermenu__name strong { display: block; font-weight: 600; }
.usermenu__name span { font-size: var(--text-xs); color: var(--ink-500); }

.dropdown {
    position: absolute; right: 0; top: calc(100% + 8px);
    min-width: 248px; background: var(--surface);
    border: 1px solid var(--ink-200); border-radius: var(--r);
    box-shadow: var(--sh-lg); padding: var(--sp-2); display: none; z-index: 70;
}
.dropdown.is-open { display: block; }
.dropdown--wide { min-width: 340px; max-width: 92vw; }
.dropdown__head { padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--ink-100); margin-bottom: var(--sp-2); }
.dropdown__head strong { display: block; }
.dropdown__head span { font-size: var(--text-xs); color: var(--ink-500); }
.dropdown__item {
    display: flex; align-items: center; gap: var(--sp-2); width: 100%;
    padding: var(--sp-2) var(--sp-3); border: 0; background: transparent;
    border-radius: var(--r-sm); font-family: inherit; font-size: var(--text-md);
    color: var(--ink-700); text-align: left; cursor: pointer;
}
.dropdown__item:hover { background: var(--ink-050); color: var(--ink-900); text-decoration: none; }
.dropdown__scroll { max-height: 340px; overflow-y: auto; }
.dropdown__empty { padding: var(--sp-5); text-align: center; color: var(--ink-500); font-size: var(--text-sm); }

.notif { display: block; padding: var(--sp-3); border-radius: var(--r-sm); }
.notif:hover { background: var(--ink-050); text-decoration: none; }
.notif strong { display: block; color: var(--ink-900); font-weight: 600; }
.notif p { margin: 2px 0 0; font-size: var(--text-sm); color: var(--ink-600); }
.notif time { font-size: var(--text-xs); color: var(--ink-400); }
.notif.is-unread { background: var(--brand-050); }

/* ---------------------------------------------------------------- content */

.content { flex: 1; padding: 11px 13px var(--sp-10); max-width: var(--content-max); width: 100%; margin: 0 auto; }

.page-head { margin-bottom: var(--sp-3); }
.page-head__row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--sp-3); }
.page-head__text { flex: 1; min-width: 200px; }
.page-head h1 { font-size: var(--text-xl); }
.page-head__sub { margin: var(--sp-1) 0 0; color: var(--ink-600); }
.page-head__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

.crumbs { display: flex; flex-wrap: wrap; gap: var(--sp-2); font-size: var(--text-sm); color: var(--ink-500); margin-bottom: var(--sp-3); }
.crumbs a { color: var(--ink-600); }

/* ---------------------------------------------------------------- cards */

/* A barely-there vertical gradient, so a card reads as a lit surface rather
   than a flat white rectangle against a near-white page. */
/* The card now carries its edge in the border rather than an ambient shadow:
   at this density a wide glow under every card reads as grey haze. */
.card {
    background: linear-gradient(180deg, var(--surface) 0%, var(--surface-raised) 100%);
    border: 1px solid var(--line);
    border-radius: var(--r); box-shadow: var(--sh-xs);
}
.card__head {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
    padding: 7px 11px; border-bottom: 1px solid var(--line-soft);
}
.card__head h2 {
    font-size: var(--text-md); font-weight: 700; color: var(--brand);
    flex: 1; min-width: 130px; letter-spacing: -.01em;
}
.card__head p { margin: 1px 0 0; font-size: var(--text-xs); color: var(--ink-500); font-weight: 400; }
.card__body { padding: 11px; }
.card__body--flush { padding: 0; }
.card__foot {
    padding: var(--sp-2) 11px; border-top: 1px solid var(--line-soft);
    background: var(--line-soft); border-radius: 0 0 var(--r) var(--r); font-size: var(--text-xs);
}

.grid { display: grid; gap: var(--gap); }
/* 150px, not 196: at this tile size the old floor left a twelve-tile dashboard
   wrapping onto three rows with slack in every one. */
.grid--kpi   { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.grid--tiles { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); }
.grid--2, .grid--3, .grid--sidebar { grid-template-columns: 1fr; }
.stack { display: grid; gap: var(--gap); }

/* ---------------------------------------------------------------- KPI */

/* Value first and largest, label above it. The tint is carried by the icon chip
   and a corner glow only - the number itself stays ink-dark so it is never the
   weakest contrast on the tile. */
.kpi {
    position: relative; display: flex; flex-direction: column; height: 100%;
    padding: 8px 10px 9px; overflow: hidden; isolation: isolate;
    /* --kpi-tint is set per tone below; the default is the brand green. */
    --kpi-tint: 0, 121, 63;
    background:
        linear-gradient(180deg, rgba(var(--kpi-tint), .055) 0%, rgba(var(--kpi-tint), 0) 58%),
        linear-gradient(180deg, var(--surface) 0%, #FAFDFB 100%);
    border: 1px solid var(--line);
    border-radius: var(--r); box-shadow: var(--sh);
    transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
/* A 3px edge in the tone's own colour. The quickest thing to read on a grid of
   twelve tiles is a coloured bar, well before the label. */
.kpi::after {
    content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
    background: linear-gradient(90deg, rgb(var(--kpi-tint)), rgba(var(--kpi-tint), .35));
}
/* The grid stretches every tile to the tallest one, so a tile with no meta line
   used to end with a block of empty space. Push the meta to the bottom instead. */
.kpi__row { flex: 0 0 auto; }
.kpi__meta { margin-top: auto; }
/* Decorative only: it must never take pointer events, and it tints rather than
   colours - it sits far below text contrast. */
.kpi::before {
    content: ""; position: absolute; inset: -30px -28px auto auto;
    width: 96px; height: 96px; border-radius: 50%;
    z-index: -1; pointer-events: none;
    background: radial-gradient(circle, rgba(var(--kpi-tint), .20) 0%, rgba(var(--kpi-tint), 0) 70%);
}
/* One tint per tone, as an r,g,b triple so the wash, the top edge and the glow
   can all be derived from a single value. */
.kpi--brand   { --kpi-tint: 0, 121, 63; }
.kpi--success { --kpi-tint: 31, 122, 43; }
.kpi--accent  { --kpi-tint: 55, 179, 75; }
.kpi--info,
.kpi--teal    { --kpi-tint: 14, 154, 138; }
.kpi--warning,
.kpi--amber   { --kpi-tint: 217, 138, 31; }
.kpi--danger,
.kpi--rose    { --kpi-tint: 179, 56, 42; }
.kpi--sky     { --kpi-tint: 46, 110, 158; }
.kpi--violet  { --kpi-tint: 140, 91, 166; }
.kpi--slate   { --kpi-tint: 75, 108, 121; }

/* brand is the default look, named explicitly so a tile can ask for it rather
   than relying on the absence of a modifier. */
/* No per-tone glow rules: --kpi-tint above drives ::before, ::after and the
   wash together, so a new tone needs one line rather than four. */
a.kpi:hover {
    text-decoration: none; transform: translateY(-1px);
    box-shadow: var(--sh); border-color: rgba(var(--kpi-tint), .38);
}

.kpi__row { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.kpi__label {
    font-size: .5938rem; font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--ink-500);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kpi__value {
    font-size: 1.3125rem; font-weight: 700; color: #102E21;
    line-height: 1; margin-top: 4px;
    font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.kpi__value small { font-size: .625rem; font-weight: 600; color: var(--ink-500); letter-spacing: 0; }
.kpi__meta {
    margin-top: 6px; padding-top: 5px; border-top: 1px solid var(--line-soft);
    font-size: .5938rem; color: var(--ink-400);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The inset highlight reads as a lit surface rather than a flat swatch. */
.kpi__icon {
    width: 20px; height: 20px; flex: 0 0 20px;
    border-radius: var(--r-sm); display: grid; place-items: center;
    color: #fff; background: linear-gradient(145deg, var(--accent), var(--brand));
    box-shadow: var(--sh-brand), inset 0 1px 0 rgba(255,255,255,.30);
}
.kpi__icon svg { width: 12px; height: 12px; }
/* One chip per tone. Each is a two-stop gradient plus a shadow in its own hue -
   a single shared shadow makes every chip read as the same green button with a
   different fill. */
.kpi--info .kpi__icon,
.kpi--teal .kpi__icon {
    background: linear-gradient(145deg, #2CC6B0, var(--teal));
    box-shadow: 0 3px 8px -4px rgba(14,154,138,.55), inset 0 1px 0 rgba(255,255,255,.30);
}
.kpi--warning .kpi__icon,
.kpi--amber .kpi__icon {
    background: linear-gradient(145deg, #F2BC5C, #D98A1F);
    box-shadow: 0 3px 8px -4px rgba(217,138,31,.55), inset 0 1px 0 rgba(255,255,255,.30);
}
.kpi--danger .kpi__icon,
.kpi--rose .kpi__icon {
    background: linear-gradient(145deg, #E08376, #B3382A);
    box-shadow: 0 3px 8px -4px rgba(179,56,42,.55), inset 0 1px 0 rgba(255,255,255,.30);
}
.kpi--sky .kpi__icon {
    background: linear-gradient(145deg, #5C9BC9, var(--chart-5));
    box-shadow: 0 3px 8px -4px rgba(46,110,158,.55), inset 0 1px 0 rgba(255,255,255,.30);
}
.kpi--violet .kpi__icon {
    background: linear-gradient(145deg, #B084C7, var(--chart-6));
    box-shadow: 0 3px 8px -4px rgba(140,91,166,.55), inset 0 1px 0 rgba(255,255,255,.30);
}
.kpi--slate .kpi__icon {
    background: linear-gradient(145deg, #8FAFBB, #4B6C79);
    box-shadow: 0 3px 8px -4px rgba(75,108,121,.55), inset 0 1px 0 rgba(255,255,255,.30);
}
/* Bright brand green, distinct from the deep default - these were identical, and
   that alone flattened half the dashboard. */
.kpi--accent .kpi__icon {
    background: linear-gradient(145deg, #5FD173, var(--accent));
    box-shadow: 0 3px 8px -4px rgba(55,179,75,.60), inset 0 1px 0 rgba(255,255,255,.34);
}
.kpi--brand .kpi__icon {
    background: linear-gradient(145deg, var(--accent), var(--brand));
    box-shadow: var(--sh-brand), inset 0 1px 0 rgba(255,255,255,.30);
}
.kpi--success .kpi__icon {
    background: linear-gradient(145deg, var(--accent), #1F7A2B);
    box-shadow: 0 3px 8px -4px rgba(31,122,43,.55), inset 0 1px 0 rgba(255,255,255,.30);
}

/* The meter under a percentage tile picks up the tile's tone instead of always
   being brand green. */
.kpi--info .meter__fill, .kpi--teal .meter__fill   { background: var(--teal); }
.kpi--sky .meter__fill                             { background: var(--chart-5); }
.kpi--violet .meter__fill                          { background: var(--chart-6); }
.kpi--amber .meter__fill                           { background: #D98A1F; }

.meter { height: 6px; background: var(--ink-100); border-radius: var(--r-full); overflow: hidden; margin-top: var(--sp-3); }
.meter__fill { height: 100%; background: var(--brand); border-radius: var(--r-full); transition: width var(--t); }
.meter__fill--warning { background: #E0A32E; }
.meter__fill--danger  { background: var(--danger); }

/* ---------------------------------------------------------------- tiles */

.tile {
    display: block; position: relative; overflow: hidden;
    background: var(--surface); border: 1px solid var(--ink-200);
    border-radius: var(--r); padding: 9px 11px; box-shadow: var(--sh-xs);
    transition: box-shadow var(--t), transform var(--t);
}
.tile::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 2px; background: var(--tile, var(--brand)); }
.tile:hover { text-decoration: none; box-shadow: var(--sh); transform: translateY(-1px); }
.tile__icon {
    width: 28px; height: 28px; border-radius: var(--r-sm); display: grid; place-items: center;
    margin-bottom: var(--sp-2); background: color-mix(in srgb, var(--tile, #00793F) 13%, white);
    color: var(--tile, var(--brand));
}
.tile__name { font-size: var(--text-md); font-weight: 700; color: var(--ink-900); }
.tile__desc { font-size: var(--text-xs); color: var(--ink-500); margin: var(--sp-1) 0 var(--sp-2);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.tile__stats { display: flex; align-items: baseline; gap: var(--sp-2); padding-top: var(--sp-2); border-top: 1px solid var(--ink-100); }
.tile__count { font-size: var(--text-xl); font-weight: 700; color: var(--ink-900); line-height: 1; }
.tile__unit  { font-size: var(--text-sm); color: var(--ink-500); }
.tile__when  { margin-left: auto; font-size: var(--text-xs); color: var(--ink-400); text-align: right; }

/* ---------------------------------------------------------------- badges */

.badge {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 1.5px 6px; border-radius: var(--r-sm);
    font-size: .625rem; font-weight: 600; white-space: nowrap;
    background: var(--neutral-bg); color: var(--neutral);
}
.badge.is-success { background: var(--success-bg); color: var(--success); }
.badge.is-warning { background: var(--warning-bg); color: var(--warning); }
.badge.is-danger  { background: var(--danger-bg);  color: var(--danger); }
.badge.is-info    { background: var(--info-bg);    color: var(--info); }
.badge.is-muted   { background: var(--ink-100);    color: var(--ink-500); }
.badge--dot::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; }

.chip {
    display: inline-flex; align-items: center; gap: 5px; padding: 1.5px 7px;
    border-radius: var(--r-sm); background: var(--ink-050);
    border: 1px solid var(--ink-200); font-size: .625rem; color: var(--ink-600);
}
.chip--chain { background: color-mix(in srgb, var(--chip, #00793F) 12%, white); border-color: transparent;
    color: color-mix(in srgb, var(--chip, #00793F) 78%, black); }
.tags { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* ---------------------------------------------------------------- buttons */

.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
    padding: 0 11px; height: var(--ctl);
    border-radius: var(--r-sm); border: 1px solid transparent;
    font-family: inherit; font-size: var(--text-md); font-weight: 600;
    cursor: pointer; white-space: nowrap; text-decoration: none;
    transition: background var(--t), border-color var(--t), color var(--t), box-shadow var(--t), transform var(--t);
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn:disabled, .btn.is-disabled { opacity: .55; cursor: not-allowed; transform: none; }

.btn--primary { background: var(--brand); color: #fff; box-shadow: var(--sh-brand); }
.btn--primary:hover:not(:disabled) { background: var(--brand-600); color: #fff; box-shadow: 0 2px 6px rgba(34,118,42,.28); }

.btn--accent { background: var(--accent); color: #fff; box-shadow: 0 4px 10px -6px rgba(55,179,75,.55); }
.btn--accent:hover:not(:disabled) { background: var(--accent-600); color: #fff; }

.btn--ghost { background: var(--surface); color: var(--ink-700); border-color: var(--ink-300); }
.btn--ghost:hover:not(:disabled) { background: var(--ink-050); color: var(--ink-900); border-color: var(--ink-400); }

.btn--subtle { background: var(--ink-050); color: var(--ink-700); }
.btn--subtle:hover:not(:disabled) { background: var(--ink-100); }

.btn--danger  { background: var(--danger); color: #fff; }
.btn--danger:hover:not(:disabled)  { background: #93291D; color: #fff; }

.btn--success { background: var(--success); color: #fff; }
.btn--success:hover:not(:disabled) { background: #17601F; color: #fff; }

.btn--sm { height: 24px; padding: 0 9px; font-size: var(--text-sm); gap: 5px; }
.btn--lg { height: 34px; padding: 0 var(--sp-6); font-size: var(--text-lg); }
.btn--block { width: 100%; }
.btn-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* ---------------------------------------------------------------- forms */

.field { margin-bottom: var(--sp-3); }
.field__label { display: block; margin-bottom: 4px; font-size: .5938rem; font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--ink-500); }
.req { color: var(--danger); }
.field__hint  { margin-top: var(--sp-1); font-size: var(--text-xs); color: var(--ink-500); }
.field__error { margin-top: var(--sp-1); font-size: var(--text-xs); color: var(--danger); font-weight: 600; }

.input, .select, .textarea {
    width: 100%; min-height: var(--ctl); padding: 5px 8px;
    border: 1px solid var(--ink-300); border-radius: var(--r-sm);
    font-family: inherit; font-size: var(--text-md); color: var(--ink-900);
    background: var(--surface); transition: border-color var(--t), box-shadow var(--t);
}
.input:focus, .select:focus, .textarea:focus {
    outline: none; border-color: var(--accent); box-shadow: 0 0 0 .2rem rgba(55,179,75,.16);
}
.input.has-error, .textarea.has-error, .select.has-error { border-color: var(--danger); }
.input:disabled, .select:disabled, .textarea:disabled { background: var(--ink-050); color: var(--ink-500); }
.textarea { min-height: 62px; resize: vertical; line-height: 1.45; }
.select {
    appearance: none; padding-right: 23px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748B' d='M6 8.5 1.5 4h9z'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 8px center;
}
.input--otp { font-family: var(--mono); letter-spacing: .5em; text-align: center; font-size: var(--text-2xl); height: 44px; }

.check { display: flex; align-items: flex-start; gap: var(--sp-2); margin-bottom: var(--sp-2); cursor: pointer; }
.check input { margin-top: 2px; width: 14px; height: 14px; accent-color: var(--brand); flex: 0 0 14px; }
.check span  { font-size: var(--text-md); color: var(--ink-700); }
.check small { display: block; font-size: var(--text-xs); color: var(--ink-500); }
.checklist { max-height: 190px; overflow-y: auto; border: 1px solid var(--ink-200); border-radius: var(--r-sm); padding: var(--sp-3); }

.form-grid { display: grid; gap: 0 var(--sp-4); grid-template-columns: 1fr; }

.filters {
    display: grid; gap: var(--sp-3); grid-template-columns: 1fr;
    padding: var(--sp-4); background: var(--surface);
    border: 1px solid var(--ink-200); border-radius: var(--r-lg); margin-bottom: var(--sp-4);
}
.filters__actions { display: flex; gap: var(--sp-2); align-items: flex-end; }

/* drop zone */
.dropzone {
    border: 2px dashed var(--ink-300); border-radius: var(--r-lg);
    padding: var(--sp-8) var(--sp-4); text-align: center; background: var(--ink-050);
    transition: border-color var(--t), background var(--t); cursor: pointer;
}
.dropzone:hover, .dropzone.is-over { border-color: var(--brand); background: var(--brand-050); }
.dropzone__icon { color: var(--brand); margin-bottom: var(--sp-3); }
.dropzone strong { display: block; color: var(--ink-900); margin-bottom: var(--sp-1); }
.dropzone input[type=file] { display: none; }
.dropzone__file {
    margin-top: var(--sp-3); padding: var(--sp-3); background: #fff;
    border: 1px solid var(--ink-200); border-radius: var(--r-sm);
    display: none; text-align: left; font-size: var(--text-sm);
}
.dropzone__file.is-shown { display: block; }

/* ---------------------------------------------------------------- tables */

.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: var(--text-md); }
/* 9px with wide tracking. Below about .11em a 9px uppercase head stops reading
   as a label and starts reading as noise. */
.table th {
    text-align: left; font-weight: 700; font-size: .5625rem;
    letter-spacing: .11em; text-transform: uppercase; color: var(--brand);
    padding: 6px 10px; border-bottom: 1px solid var(--line);
    background: linear-gradient(180deg, #F7FAF8, #F2F7F4); white-space: nowrap;
}
.table td { padding: 6px 10px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr { transition: background .12s ease; }
.table tbody tr:hover { background: #F6FBF8; }
.table__num { text-align: right; font-variant-numeric: tabular-nums; }
.table__title { font-weight: 650; color: var(--ink-900); }
.table__sub { display: block; font-size: var(--text-xs); color: var(--ink-500); margin-top: 1px; }
.table__actions { text-align: right; white-space: nowrap; }
.table--compact td, .table--compact th { padding: var(--sp-2) var(--sp-3); }

.empty { padding: var(--sp-10) var(--sp-5); text-align: center; color: var(--ink-500); }
.empty__icon { color: var(--ink-300); margin-bottom: var(--sp-3); }
.empty h3 { font-size: var(--text-lg); color: var(--ink-700); margin-bottom: var(--sp-1); }
.empty p  { font-size: var(--text-sm); max-width: 46ch; margin: 0 auto var(--sp-4); }

.pager { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); padding: var(--sp-3) var(--sp-5); border-top: 1px solid var(--ink-100); }
.pager__info { font-size: var(--text-sm); color: var(--ink-500); margin-right: auto; }
.pager a, .pager span.current {
    min-width: 34px; height: 34px; padding: 0 var(--sp-2);
    display: inline-grid; place-items: center; border: 1px solid var(--ink-200);
    border-radius: var(--r-sm); font-size: var(--text-sm); color: var(--ink-700);
}
.pager a:hover { background: var(--ink-050); text-decoration: none; }
.pager span.current { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 700; }
.pager span.gap { border: 0; }

/* ---------------------------------------------------------------- alerts */

.alert {
    display: flex; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4);
    border-radius: var(--r-sm); border: 1px solid transparent;
    margin-bottom: var(--sp-4); font-size: var(--text-md);
}
.alert__icon { flex: 0 0 18px; margin-top: 2px; }
.alert__body { flex: 1; min-width: 0; }
.alert strong { display: block; margin-bottom: 2px; }
.alert p:last-child { margin-bottom: 0; }
.alert--success { background: var(--success-bg); border-color: #B7E3BE; color: #14541D; }
.alert--error   { background: var(--danger-bg);  border-color: #F0BDB4; color: #7E2418; }
.alert--warning { background: var(--warning-bg); border-color: #EBCD9A; color: #6B4106; }
.alert--info    { background: var(--info-bg);    border-color: #B3D6E9; color: #14455F; }

.flashes {
    position: fixed; top: calc(var(--topbar-h) + 12px); right: var(--sp-4);
    z-index: 80; width: min(410px, calc(100vw - 2rem)); display: grid; gap: var(--sp-2);
}
.flashes .alert { box-shadow: var(--sh-lg); margin: 0; }

.banner-archived {
    display: flex; gap: var(--sp-3); align-items: flex-start; padding: var(--sp-4);
    background: repeating-linear-gradient(135deg, #FDF1DE, #FDF1DE 12px, #FAE8CB 12px, #FAE8CB 24px);
    border: 1px solid #E3B269; border-left: 4px solid #C98A21;
    border-radius: var(--r-sm); margin-bottom: var(--sp-4); color: #6B4106;
}
.banner-archived strong { display: block; font-size: var(--text-lg); }

/* test-mode strip */
.testbar {
    background: var(--accent); color: #fff; text-align: center;
    padding: 6px var(--sp-4); font-size: var(--text-xs); font-weight: 650; letter-spacing: .02em;
}
.testbar a { color: #fff; text-decoration: underline; }

/* ---------------------------------------------------------------- tabs */

.tabs { display: flex; gap: var(--sp-1); border-bottom: 1px solid var(--ink-200); margin-bottom: var(--sp-4); overflow-x: auto; }
.tabs a {
    padding: var(--sp-3) var(--sp-4); font-size: var(--text-md); font-weight: 600;
    color: var(--ink-600); border-bottom: 2px solid transparent; white-space: nowrap;
}
.tabs a:hover { color: var(--ink-900); text-decoration: none; }
.tabs a.is-active { color: var(--brand-700); border-bottom-color: var(--brand); }

/* ---------------------------------------------------------------- charts */

.chart { position: relative; width: 100%; }
.chart--sm { height: 190px; }
.chart--md { height: 280px; }
.chart--lg { height: 330px; }

/* ---------------------------------------------------------------- timeline */

.timeline { position: relative; padding-left: var(--sp-6); }
.timeline::before { content: ""; position: absolute; left: 7px; top: 4px; bottom: 4px; width: 2px; background: var(--ink-100); }
.tl { position: relative; padding-bottom: var(--sp-4); }
.tl:last-child { padding-bottom: 0; }
.tl__dot { position: absolute; left: calc(-1 * var(--sp-6) + 2px); top: 4px; width: 12px; height: 12px; border-radius: 50%; background: #fff; border: 2px solid var(--ink-300); }
.tl__dot.is-success { border-color: var(--success); background: var(--success); }
.tl__dot.is-warning { border-color: #E0A32E; background: #E0A32E; }
.tl__dot.is-danger  { border-color: var(--danger); background: var(--danger); }
.tl__dot.is-brand   { border-color: var(--brand); background: var(--brand); }
.tl__title { font-weight: 650; color: var(--ink-900); }
.tl__meta  { font-size: var(--text-xs); color: var(--ink-500); }
.tl__body  { font-size: var(--text-sm); color: var(--ink-600); margin-top: 2px; }

/* ---------------------------------------------------------------- approvals */

.person {
    display: flex; align-items: center; gap: var(--sp-3);
    padding: var(--sp-3) 0; border-bottom: 1px solid var(--ink-100);
}
.person:last-child { border-bottom: 0; }
.person__seq {
    width: 28px; height: 28px; flex: 0 0 28px; border-radius: 50%;
    display: grid; place-items: center; background: var(--ink-100); color: var(--ink-600);
    font-size: var(--text-xs); font-weight: 700;
}
.person.is-done .person__seq { background: var(--success-bg); color: var(--success); }
.person.is-rejected .person__seq { background: var(--danger-bg); color: var(--danger); }
.person__who { flex: 1; min-width: 0; }
.person__who strong { display: block; font-weight: 650; color: var(--ink-900); }
.person__who span { font-size: var(--text-xs); color: var(--ink-500); }

.proof {
    font-family: var(--mono); font-size: var(--text-xs); word-break: break-all;
    color: var(--ink-600); background: var(--ink-050); padding: var(--sp-2) var(--sp-3);
    border-radius: var(--r-sm); border: 1px solid var(--ink-200);
}

/* ---------------------------------------------------------------- PDF viewer */

.viewer { position: relative; background: var(--surface); border: 1px solid var(--ink-200); border-radius: var(--r-lg); overflow: hidden; }
.viewer__bar {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--ink-200);
    background: var(--ink-050); font-size: var(--text-sm);
}
.viewer__stage { position: relative; background: #55606B; padding: var(--sp-4); min-height: 460px; text-align: center; overflow: auto; }
.viewer__stage canvas {
    max-width: 100%; height: auto; box-shadow: 0 4px 18px rgba(0,0,0,.32);
    margin: 0 auto var(--sp-4); background: #fff; display: block;
}
.viewer__mark {
    position: absolute; inset: 0; pointer-events: none; z-index: 3; overflow: hidden;
    opacity: .13; display: flex; flex-wrap: wrap; align-content: space-around; justify-content: space-around; gap: var(--sp-8);
}
.viewer__mark span { transform: rotate(-28deg); font-size: .85rem; font-weight: 700; letter-spacing: .08em; color: #0F172A; white-space: nowrap; }
.viewer__loading { color: #E2E8F0; padding: var(--sp-10); font-size: var(--text-sm); }

.pdf-nav { display: flex; align-items: center; gap: var(--sp-2); }
.pdf-nav__page { font-variant-numeric: tabular-nums; min-width: 76px; text-align: center; }

/* ---------------------------------------------------------------- login */

/* ---------------------------------------------------------------- auth pages

   Sign in, forgot password, reset password and the forced password change.

   A photograph carries the brand, with a green scrim over it. The scrim is not
   decoration: the image is uncontrolled artwork, and white text on it is only
   legible because the gradients guarantee contrast underneath.                */

.authbody { background: var(--brand-900); }

.auth {
    --auth-image: none;
    position: relative; min-height: 100vh;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    padding: 24px 16px;
    /* Two layers over the photo: a directional brand tint, and a wide radial
       vignette that darkens the edges and lifts the centre where the card sits.
       One flat gradient on its own washes the photograph out to a green sheet. */
    background-image:
        /* radial-gradient(120% 95% at 50% 45%, rgba(2,26,18,.10) 0%, rgba(2,26,18,.52) 62%, rgba(1,18,12,.78) 100%),
        linear-gradient(118deg, rgba(3,34,23,.72) 0%, rgba(0,96,50,.46) 48%, rgba(14,154,138,.30) 100%),
        */
        var(--auth-image);
    background-size: cover, cover, cover;
    background-position: center, center, center;
    background-repeat: no-repeat, no-repeat, no-repeat;
    background-attachment: fixed, fixed, fixed;
}

.auth__shell {
    width: 100%; max-width: 940px;
    display: grid; grid-template-columns: 1fr;
    border-radius: var(--r-lg); overflow: hidden;
    box-shadow: 0 30px 80px rgba(2,20,13,.45);
}

/* Left: frosted brand panel over the photo. Dark enough for white body text at
   this size over an unknown image, whatever the scrim lets through. */
.auth__brand {
    display: none; flex-direction: column;
    padding: 44px 40px; color: #fff;
    background: linear-gradient(160deg, rgba(2,26,17,.80), rgba(4,52,34,.62));
    backdrop-filter: blur(8px) saturate(120%);
    -webkit-backdrop-filter: blur(8px) saturate(120%);
    border-right: 1px solid rgba(255,255,255,.10);
}
/* A square white plate, never rounded. The plate stays because the logo is dark
   green on transparent and would vanish against the panel. */
.auth__plate {
    height: 48px; width: auto; align-self: flex-start; margin-bottom: 26px;
    background: #fff; border-radius: 0; padding: 8px 13px;
}
.auth__brandtitle { font-size: 1.25rem; font-weight: 700; line-height: 1.3; color: #fff; margin: 0 0 10px; }
.auth__brandtext { font-size: .8125rem; color: rgba(255,255,255,.82); margin: 0 0 20px; max-width: 34ch; }
.auth__points { list-style: none; padding: 0; margin: 0 0 auto; }
.auth__points li {
    display: flex; align-items: center; gap: 12px;
    font-size: .78rem; color: rgba(255,255,255,.90); padding: 7px 0;
}
.auth__points li span {
    width: 26px; height: 26px; flex: 0 0 26px; border-radius: var(--r-sm);
    display: grid; place-items: center;
    background: rgba(255,255,255,.14); color: var(--accent-200);
}
.auth__brandfoot { font-size: .6875rem; color: rgba(255,255,255,.6); margin: 26px 0 0; }

/* Right: the form panel - near-opaque, because a form must stay readable. */
.auth__panel { background: rgba(255,255,255,.97); padding: 30px 28px; }
.auth__logo { display: block; height: 42px; width: auto; margin: 0 auto 18px; border-radius: 0; }
.auth__title { font-size: 1.25rem; font-weight: 750; color: var(--brand); margin: 0 0 5px; }
.auth__sub { font-size: .8125rem; color: var(--ink-500); margin: 0 0 20px; }
.auth__mode {
    display: flex; align-items: center; gap: 7px; margin: 0 0 var(--sp-4);
    padding: 9px var(--sp-4); border-radius: var(--r-sm);
    background: var(--warning-bg); color: var(--warning);
    font-size: var(--text-xs); line-height: 1.45;
}
.auth__mode svg { flex: 0 0 14px; }
.auth__notice {
    display: flex; gap: 7px; align-items: flex-start;
    font-size: .6875rem; color: var(--ink-500); text-align: left;
    margin: 20px 0 0; padding-top: 13px; border-top: 1px solid var(--line);
}
.auth__notice svg { flex: 0 0 13px; margin-top: 2px; }
.auth__foot { text-align: center; font-size: .6875rem; color: rgba(255,255,255,.72); margin: 18px 0 0; }

@media (min-width: 992px) {
    .auth__shell { grid-template-columns: 1.05fr .95fr; }
    .auth__brand { display: flex; }
    .auth__logo { display: none; }
    .auth__foot { display: none; }
}
@media (max-width: 991.98px) {
    .auth__shell { max-width: 460px; }
    .auth__title, .auth__sub { text-align: center; }
}
@media (max-width: 575.98px) {
    .auth__panel { padding: 30px 22px; }
}

/* Confirmation and dead-end states: link sent, password updated, link expired. */
.authdone { text-align: center; }
.authdone__icon {
    width: 58px; height: 58px; border-radius: 50%;
    display: grid; place-items: center; margin: 4px auto 18px;
    background: var(--accent-100); color: var(--brand);
}
.authdone__icon--ok  { background: var(--accent); color: #fff; }
.authdone__icon--bad { background: #FDECEC; color: #A32020; }
.authdone p { font-size: .88rem; color: var(--ink-700); margin: 0 0 var(--sp-4); }
.authdone .btn { margin-top: var(--sp-2); }

/* An input with a leading icon. The icon prefix owns the left edge; the input
   keeps real padding so the text never crowds the glyph. */
.inputgroup { position: relative; display: flex; align-items: stretch; }
.inputgroup__icon {
    position: absolute; left: 0; top: 0; bottom: 0; width: 38px;
    display: grid; place-items: center;
    color: var(--ink-400); pointer-events: none; z-index: 1;
}
.inputgroup .input { padding-left: 38px; }
.inputgroup--pw .input { padding-right: 44px; }
.inputgroup:focus-within .inputgroup__icon { color: var(--brand); }

/* Password reveal toggle. */
.pw__toggle {
    position: absolute; right: 3px; top: 50%; transform: translateY(-50%);
    width: 34px; height: 34px; display: grid; place-items: center;
    background: none; border: 0; border-radius: var(--r-sm);
    color: var(--ink-400); cursor: pointer; z-index: 2;
}
.pw__toggle:hover { color: var(--brand); background: var(--accent-100); }
.pw__toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.pwmeter { display: flex; align-items: center; gap: var(--sp-3); margin-top: 8px; }
.pwmeter__track { flex: 1; height: 5px; border-radius: 4px; background: #E9EDEB; overflow: hidden; }
.pwmeter__fill {
    display: block; height: 100%; width: 0; border-radius: 4px;
    background: var(--danger);
    transition: width .22s ease, background-color .22s ease;
}
.pwmeter__label {
    font-size: var(--text-xs); font-weight: 650; color: var(--ink-500);
    min-width: 8ch; text-align: right;
}
.pwmeter.is-weak   .pwmeter__fill { background: var(--danger); }
.pwmeter.is-fair   .pwmeter__fill { background: #E8A33D; }
.pwmeter.is-good   .pwmeter__fill { background: var(--accent); }
.pwmeter.is-strong .pwmeter__fill { background: var(--brand); }

/* The CAPTCHA that appears once an address has failed repeatedly. */
.captcha { display: flex; align-items: stretch; gap: var(--sp-3); }
.captcha__img {
    height: 44px; width: 150px; flex: 0 0 150px;
    border: 1px solid var(--ink-300); border-radius: var(--r-sm);
    background: #fff; display: block; object-fit: cover;
}
.captcha__side { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; }
.captcha__reload {
    align-self: flex-start; background: none; border: 0; padding: 0;
    font-family: inherit; font-size: var(--text-xs); color: var(--brand);
    cursor: pointer; text-decoration: underline;
}

.auth__link { text-align: right; margin: -4px 0 20px; font-size: var(--text-sm); }
.auth__aside-note {
    margin: var(--sp-4) 0 0; padding: var(--sp-3) var(--sp-4);
    background: var(--accent-100); border-radius: var(--r-sm);
    font-size: var(--text-xs); color: var(--ink-600); line-height: 1.6;
}

/* The email preview. White, because that is the canvas an inbox gives it - a
   tinted surface behind a 600px email misrepresents the contrast. */
.mailpreview {
    width: 100%; height: 520px; display: block;
    border: 1px solid var(--ink-200); border-radius: var(--r-sm);
    background: #fff;
}
@media (max-width: 767px) { .mailpreview { height: 380px; } }

/* An inline edit row. The form replaces the whole row, so it needs its own
   spacing rather than inheriting the cell padding. */
.masterform { display: grid; gap: var(--sp-3); padding: var(--sp-2) 0; }
@media (min-width: 768px) { .masterform { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.masterform .btn-row { grid-column: 1 / -1; }
/* A deactivated row stays legible but clearly not in play. */
.table tbody tr.is-dim td { opacity: .58; }
.table tbody tr.is-dim .badge { opacity: 1; }

.ticklist { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-3); }
.ticklist li { display: flex; gap: var(--sp-3); align-items: flex-start; font-size: var(--text-sm); }
.ticklist svg { flex: 0 0 16px; margin-top: 2px; color: var(--brand); }

/* Demo accounts. Two per row on anything but a phone: eight full-width rows
   pushed the sign-in button off the fold on a laptop. */
.demo {
    margin-top: var(--sp-4); padding: var(--sp-4);
    background: rgba(255,255,255,.94); border: 1px solid var(--line);
    border-radius: var(--r); box-shadow: var(--sh-sm);
}
.demo summary {
    cursor: pointer; font-size: var(--text-sm); font-weight: 650;
    color: var(--brand); list-style: none;
}
.demo summary::-webkit-details-marker { display: none; }
.demo summary::before {
    content: "▸"; display: inline-block; width: 1em;
    transition: transform var(--t); color: var(--ink-400);
}
.demo[open] summary::before { transform: rotate(90deg); }
.demo__hint { margin: var(--sp-3) 0 var(--sp-3); font-size: var(--text-xs); color: var(--ink-500); }

.demo__grid { display: grid; grid-template-columns: 1fr; gap: 6px; margin-bottom: var(--sp-3); }
@media (min-width: 480px) { .demo__grid { grid-template-columns: 1fr 1fr; } }

.demoacct {
    display: flex; align-items: center; gap: var(--sp-2); width: 100%;
    padding: 8px 10px; text-align: left; cursor: pointer;
    background: var(--surface); border: 1px solid var(--ink-200);
    border-radius: var(--r-sm); font-family: inherit;
    transition: border-color var(--t), background var(--t), transform var(--t);
}
.demoacct:hover {
    border-color: var(--accent); background: var(--accent-100);
    transform: translateY(-1px);
}
.demoacct:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.demoacct__icon {
    flex: 0 0 26px; width: 26px; height: 26px; border-radius: 8px;
    display: grid; place-items: center;
    background: linear-gradient(145deg, var(--accent), var(--brand)); color: #fff;
}
.demoacct__text { min-width: 0; line-height: 1.25; }
.demoacct__text strong {
    display: block; font-size: var(--text-xs); font-weight: 650; color: var(--ink-900);
}
.demoacct__mail {
    display: block; font-family: var(--mono); font-size: .6875rem;
    color: var(--ink-500); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Filling two fields the user cannot see happening needs saying out loud. */
.demoacct.is-filled { border-color: var(--brand); background: var(--brand-050); }
.demoacct.is-filled .demoacct__text strong::after {
    content: " — filled"; font-weight: 600; color: var(--brand);
}

/* ---------------------------------------------------------------- misc */

.muted  { color: var(--ink-500); }
.small  { font-size: var(--text-sm); }
.xsmall { font-size: var(--text-xs); }
.mono   { font-family: var(--mono); }
.nowrap { white-space: nowrap; }
.right  { text-align: right; }
.center { text-align: center; }
.mt-4 { margin-top: var(--sp-4); }
.mb-0 { margin-bottom: 0; }
.mb-4 { margin-bottom: var(--sp-4); }
.flex { display: flex; gap: var(--sp-3); align-items: center; }
.flex-wrap { flex-wrap: wrap; }
.between { display: flex; gap: var(--sp-3); align-items: center; justify-content: space-between; }

.dl { display: grid; gap: var(--sp-3); grid-template-columns: 1fr; margin: 0; }
.dl > div { min-width: 0; }
.dl dt { font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-500); }
.dl dd { margin: 2px 0 0; color: var(--ink-800); word-break: break-word; }

.statline { display: flex; flex-wrap: wrap; gap: var(--sp-5); }
.statline dt { font-size: var(--text-xs); color: var(--ink-500); text-transform: uppercase; letter-spacing: .05em; font-weight: 700; }
.statline dd { margin: 2px 0 0; font-size: var(--text-xl); font-weight: 700; color: var(--ink-900); font-variant-numeric: tabular-nums; }

.hint {
    padding: var(--sp-3) var(--sp-4); border-radius: var(--r-sm);
    background: var(--brand-050); border: 1px solid var(--brand-100);
    font-size: var(--text-sm); color: var(--ink-700);
}

/* ================================================================ v2 panels
   The dashboard's decision-oriented components.

   These sit alongside .card rather than replacing it: .panel is a denser
   sibling with a rule-bordered head, and every page outside the v2 set keeps
   working untouched. Class names already in use are not redefined here - that
   is what let all 28 pages pick up both the original port and the compaction
   without 28 edits, and it is the only reason this section can be added at all.

   Geometry comes from --row / --gap / --ctl in tokens.css. Nothing here
   re-chooses a row height or a gap.
   ========================================================================= */

/* One tint per tone, as an r,g,b triple, exactly as --kpi-tint already works.
   Every tonal thing below - icon chip, pipeline stage, feed marker, month
   column - derives its background, its foreground and its edge from this one
   value, so adding a tone is one line rather than four rules. */
.tone--brand   { --tone: 0, 121, 63; }
.tone--success { --tone: 31, 122, 43; }
.tone--accent  { --tone: 55, 179, 75; }
.tone--teal    { --tone: 14, 154, 138; }
.tone--info    { --tone: 46, 110, 158; }
.tone--sky     { --tone: 46, 110, 158; }
.tone--warning { --tone: 217, 138, 31; }
.tone--danger  { --tone: 179, 56, 42; }
.tone--violet  { --tone: 140, 91, 166; }
.tone--slate   { --tone: 75, 108, 121; }
.tone--muted   { --tone: 100, 116, 139; }

/* Square tinted icon holder. Sized by its modifier, never by inline style. */
.iconchip {
    --tone: 0, 121, 63;
    display: grid; place-items: center; flex: 0 0 20px;
    width: 20px; height: 20px; border-radius: var(--r-sm);
    background: rgba(var(--tone), .12); color: rgb(var(--tone));
}
.iconchip--md { flex-basis: 24px; width: 24px; height: 24px; }
.iconchip--lg { flex-basis: 30px; width: 30px; height: 30px; border-radius: var(--r); }

/* ---- 12-column grid ---------------------------------------------------- */
.g12 { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--gap); }
.g12 > .col-4  { grid-column: span 12; }
.g12 > .col-6  { grid-column: span 12; }
.g12 > .col-8  { grid-column: span 12; }
.g12 > .col-12 { grid-column: span 12; }

/* ---- section rule ------------------------------------------------------ */
.sec { display: flex; align-items: center; gap: var(--sp-2); margin: var(--sp-5) 0 var(--sp-2); }
.sec > h2 {
    margin: 0; font-size: 9.5px; font-weight: 700; letter-spacing: .13em;
    text-transform: uppercase; color: var(--ink-500); white-space: nowrap;
}
.sec__rule { flex: 1; height: 1px; background: var(--line); }
.sec__why  { font-size: var(--text-xs); color: var(--ink-400); white-space: nowrap; }
.sec__link, .panel__link {
    display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
    font-size: var(--text-xs); font-weight: 600; color: var(--brand); text-decoration: none;
}
.sec__link:hover, .panel__link:hover { color: var(--brand-700); text-decoration: underline; }

/* ---- panel ------------------------------------------------------------- */
.panel {
    display: flex; flex-direction: column; min-width: 0;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r); overflow: hidden; box-shadow: var(--sh-xs);
}
.panel__head {
    display: flex; align-items: center; gap: var(--sp-2);
    padding: 7px 11px; border-bottom: 1px solid var(--line-soft);
}
.panel__head > h3 { margin: 0; font-size: var(--text-md); font-weight: 700; white-space: nowrap; }
.panel__say {
    min-width: 0; font-size: var(--text-xs); color: var(--ink-500);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.panel__count {
    --tone: 179, 56, 42;
    padding: 1px 7px; border-radius: var(--r-full);
    background: rgba(var(--tone), .12); color: rgb(var(--tone));
    font-size: 10px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.panel__link { margin-left: auto; }
.panel__body { padding: var(--sp-3) 11px; }
.panel__body--flush { padding: 0; }

/* A computed finding, shown only when it is true - see panels.php. */
.panel__note {
    display: flex; align-items: center; gap: 6px;
    padding: 0 11px var(--sp-3); font-size: var(--text-xs); color: var(--ink-500);
}
.panel__note--top { padding-top: var(--sp-3); }

/* ---- KPI additions: sparkline, delta chip, caption --------------------- */
.kpi__unit  { font-size: 10.5px; font-weight: 600; color: var(--ink-500); }
.kpi__delta {
    display: inline-flex; align-items: center; gap: 2px; margin-left: auto;
    font-size: 10px; font-weight: 700; font-variant-numeric: tabular-nums;
}
/* Good and bad, not up and down: a falling publish cycle is good news and a
   rising one is not, so the colour follows the judgement while the arrow keeps
   following the direction. The arrow is why this still reads without colour. */
.kpi__delta--good { color: var(--success); }
.kpi__delta--bad  { color: var(--danger); }
.kpi__delta--flat { color: var(--ink-400); }
.kpi__spark { display: block; width: 100%; height: 20px; margin-top: 5px; }
.kpi__cap {
    margin-top: auto; padding-top: 2px;
    font-size: 9.5px; color: var(--ink-400);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kpi__figure { display: flex; align-items: baseline; gap: 4px; margin-top: 4px; }
.kpi__figure > b { font-size: var(--text-2xl); font-weight: 700; line-height: 1; }
.kpi--alarm .kpi__figure > b { color: var(--danger); }

/* ---- period tabs ------------------------------------------------------- */
.rangetabs {
    display: inline-flex; overflow: hidden;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm);
}
.rangetabs > a {
    height: var(--ctl); display: inline-flex; align-items: center; padding: 0 10px;
    border-left: 1px solid var(--line-soft);
    font-size: var(--text-xs); font-weight: 600; color: var(--ink-500); text-decoration: none;
}
.rangetabs > a:first-child { border-left: 0; }
.rangetabs > a:hover { background: var(--brand-050); color: var(--brand-700); }
.rangetabs > a.is-active { background: var(--brand); color: #fff; }

/* ---- standing strip ---------------------------------------------------- */
.standing {
    display: flex; align-items: center; gap: 11px; padding: var(--sp-4);
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
}
.standing__text { min-width: 0; }
.standing__text > b { display: block; font-size: var(--text-md); }
.standing__text > span { font-size: var(--text-sm); color: var(--ink-500); }
.standing > .btn { margin-left: auto; flex: 0 0 auto; }

/* ---- lifecycle pipeline ------------------------------------------------ */
.flow { display: flex; gap: 3px; padding: 11px; }
.flow__stage {
    --tone: 0, 121, 63;
    flex: 1; min-width: 0; padding: 8px 10px 8px 17px;
    background: rgba(var(--tone), .10); color: rgb(var(--tone));
    text-decoration: none;
    clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 50%, calc(100% - 9px) 100%, 0 100%, 9px 50%);
}
.flow__stage:first-child {
    padding-left: 11px; border-radius: var(--r-sm) 0 0 var(--r-sm);
    clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 50%, calc(100% - 9px) 100%, 0 100%);
}
.flow__stage:last-child {
    border-radius: 0 var(--r-sm) var(--r-sm) 0;
    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 9px 50%);
}
.flow__stage:hover { background: rgba(var(--tone), .18); }
.flow__label {
    display: flex; align-items: center; gap: 5px; opacity: .85;
    font-size: 9.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
}
.flow__value { margin-top: 2px; font-size: 20px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.flow__meta  { font-size: 10px; opacity: .75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- coverage donut ---------------------------------------------------- */
.donut { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-3) 11px; }
.donut__svg { flex: 0 0 98px; width: 98px; height: 98px; }
.donut__key { min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.donut__key > div { display: flex; align-items: center; gap: 6px; font-size: var(--text-xs); color: var(--ink-700); }
.donut__key i { flex: 0 0 8px; width: 8px; height: 8px; border-radius: 2px; }
.donut__key b { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.donut__total { border-top: 1px solid var(--line-soft); padding-top: 5px; color: var(--ink-500); }

/* ---- value-chain bars -------------------------------------------------- */
.vbars { display: flex; flex-direction: column; gap: 7px; padding: var(--sp-3) 11px; }
.vbars__row { display: grid; grid-template-columns: 1fr 90px 42px; align-items: center; gap: var(--sp-2); }
.vbars__name { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: var(--text-xs); }
.vbars__name > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vbars__track { height: 6px; border-radius: 3px; background: var(--ink-100); overflow: hidden; }
.vbars__fill { display: block; height: 100%; border-radius: 3px; background: var(--bar, var(--brand)); }
.vbars__num { text-align: right; font-size: var(--text-xs); color: var(--ink-500); font-variant-numeric: tabular-nums; }

/* ---- month columns ----------------------------------------------------- */
.months { display: flex; align-items: flex-end; gap: 5px; padding: var(--sp-3) 11px; }
.months__col { flex: 1; min-width: 0; text-align: center; }
.months__bar {
    --tone: 0, 121, 63;
    display: grid; place-items: center; border-radius: 5px;
    background: rgba(var(--tone), .13); color: rgb(var(--tone));
    font-size: var(--text-lg); font-weight: 700; font-variant-numeric: tabular-nums;
}
.months__label {
    margin-top: 4px; font-size: 9.5px; font-weight: 600; color: var(--ink-500);
    letter-spacing: .04em; text-transform: uppercase;
}

/* ---- SLA meter in a table cell ----------------------------------------- */
.sla { display: flex; align-items: center; gap: 6px; }
.sla__age { font-size: var(--text-xs); color: var(--ink-500); font-variant-numeric: tabular-nums; }
.sla__age--late { color: var(--danger); font-weight: 700; }
.sla__track { flex: 0 0 44px; width: 44px; height: 4px; border-radius: 2px; background: var(--ink-100); overflow: hidden; }
.sla__fill  { display: block; height: 100%; border-radius: 2px; background: var(--accent); }
.sla__track--warm .sla__fill { background: #D98A1F; }
.sla__track--hot  .sla__fill { background: var(--danger); }

/* ---- activity feed ----------------------------------------------------- */
.feed__item {
    display: flex; align-items: flex-start; gap: var(--sp-2);
    padding: 6px 11px; border-bottom: 1px solid var(--line-soft);
}
.feed__item:last-child { border-bottom: 0; }
.feed__item p { margin: 0; font-size: var(--text-xs); line-height: 1.4; }
.feed__item p b { font-weight: 650; }
.feed__item time { font-size: 10px; color: var(--ink-400); }

/* ---- plain list rows (never opened) ------------------------------------ */
.listrow {
    display: flex; align-items: center; gap: var(--sp-2);
    padding: 7px 11px; border-bottom: 1px solid var(--line-soft); text-decoration: none;
}
.listrow:last-child { border-bottom: 0; }
.listrow:hover { background: var(--brand-050); }
.listrow__text { flex: 1; min-width: 0; }
.listrow__text > b { display: block; font-size: var(--text-sm); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.listrow__text > span { font-size: var(--text-xs); color: var(--ink-400); }
.listrow__num { flex: 0 0 auto; text-align: right; }
.listrow__num > b { display: block; font-size: var(--text-lg); font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.listrow__num > span { font-size: 9px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-400); }

/* ---- table foot -------------------------------------------------------- */
.tfoot {
    display: flex; align-items: center; gap: var(--sp-2);
    padding: 6px 11px; border-top: 1px solid var(--line-soft);
    font-size: var(--text-xs); color: var(--ink-500);
}
.tfoot > .pager { margin-left: auto; padding: 0; border: 0; }

/* ---- mini person cell --------------------------------------------------
   NOT called .person: that name has been taken since the approvals section
   above (a bordered list row with .person__seq / .person__who) and is used by
   access_requests.php, approve_action.php, review_action.php and sop_view.php.
   Reusing it here redefined the gap on all four of those pages without touching
   one of them - which is precisely why class names in this file are additive
   and never reused. */
.usercell { display: flex; align-items: center; gap: 6px; min-width: 0; }
.usercell > .avatar { flex: 0 0 20px; width: 20px; height: 20px; font-size: 8.5px; }
.usercell > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- compact filter bar ------------------------------------------------
   One wrapping row rather than a labelled grid. The labels move into the
   controls themselves (each select's first option names its own axis), which is
   what lets eight filters sit in the height the grid spent on two. Every control
   keeps a real <label>, visually hidden, so the form still reads to a screen
   reader exactly as it did. */
.filterbar {
    display: flex; flex-wrap: wrap; align-items: center; gap: 7px;
    padding: var(--sp-2) 9px;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
}
.filterbar__search {
    display: flex; align-items: center; gap: 6px;
    flex: 1 1 190px; min-width: 150px; height: var(--ctl);
    padding: 0 8px; border: 1px solid var(--line); border-radius: var(--r-sm); color: var(--ink-400);
}
.filterbar__search input { width: 100%; border: 0; outline: 0; font: inherit; font-size: var(--text-sm); color: var(--ink-900); background: none; }
.filterbar select {
    height: var(--ctl); max-width: 168px; min-width: 0; padding: 0 8px;
    border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface);
    font: inherit; font-size: var(--text-sm); color: var(--ink-900); cursor: pointer;
}
.filterbar__check { display: flex; align-items: center; gap: 5px; font-size: var(--text-sm); color: var(--ink-700); white-space: nowrap; cursor: pointer; }
.filterbar__end { margin-left: auto; display: flex; align-items: center; gap: 9px; }
.filterbar__hits { display: inline-flex; align-items: center; gap: 5px; font-size: var(--text-xs); color: var(--ink-500); }
.filterbar__hits b { color: var(--ink-900); font-weight: 700; font-variant-numeric: tabular-nums; }

/* ---- status mix strip --------------------------------------------------
   The shape of the register in 150px, in the panel head. Each segment is
   flex-weighted by its count, so it needs no axis and no numbers. */
.mixbar { display: flex; height: 6px; width: 150px; border-radius: 3px; overflow: hidden; }
.mixbar > i { display: block; min-width: 0; }

/* ---- read-count bar ---------------------------------------------------- */
.rdbar { display: flex; align-items: center; gap: 6px; }
.rdbar__num { font-size: var(--text-xs); color: var(--ink-500); font-variant-numeric: tabular-nums; }
.rdbar__track { flex: 0 0 46px; width: 46px; height: 4px; border-radius: 2px; background: var(--ink-100); overflow: hidden; }
.rdbar__fill { display: block; height: 100%; border-radius: 2px; background: var(--neutral); }

/* ---- segmented counts --------------------------------------------------
   A filter strip that shows what each filter would return before it is used.
   These are links, not buttons: each is a real URL, so a stage can be sent to
   somebody, bookmarked, or opened in a second tab. */
.segbar {
    display: flex; flex-wrap: wrap; overflow: hidden;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
}
.segbar__item {
    position: relative; flex: 1 1 auto; min-width: 124px;
    display: flex; align-items: center; gap: var(--sp-2);
    padding: var(--sp-2) 11px; border-left: 1px solid var(--line-soft);
    text-decoration: none; color: inherit;
}
.segbar__item:first-child { border-left: 0; }
.segbar__item:hover { background: var(--brand-050); }
.segbar__item.is-active { background: var(--brand-050); }
.segbar__item.is-active::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--brand);
}
.segbar__text { min-width: 0; }
.segbar__label {
    display: block; font-size: 9.5px; font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--ink-500); white-space: nowrap;
}
.segbar__item.is-active .segbar__label { color: var(--brand-700); }
.segbar__value { display: block; margin-top: 1px; font-size: var(--text-2xl); font-weight: 700; line-height: 1.05; font-variant-numeric: tabular-nums; }
.segbar__value--alarm { color: var(--danger); }

/* ---- stepper -----------------------------------------------------------
   Says how many stages this form has and which one the fields belong to. It is
   a signpost, not a wizard: every field stays on one page and in the tab order,
   because a genuine multi-step form would lose a half-filled upload. */
.steps {
    display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2);
    padding: var(--sp-2) 11px; border-bottom: 1px solid var(--line-soft); background: var(--ink-050);
}
.steps__step { display: flex; align-items: center; gap: 6px; font-size: var(--text-xs); font-weight: 600; color: var(--ink-400); }
.steps__step > i {
    display: grid; place-items: center; width: 17px; height: 17px; border-radius: 50%;
    background: var(--ink-100); color: var(--ink-500);
    font-size: 9.5px; font-weight: 700; font-style: normal;
}
.steps__step.is-current { color: var(--brand-700); }
.steps__step.is-current > i { background: var(--brand); color: #fff; }
.steps__line { flex: 1; min-width: 12px; height: 1px; background: var(--line); }

/* ---- sticky save bar ---------------------------------------------------
   On a form this long the submit button is otherwise below the fold from the
   first field onwards. It sticks to the bottom of the scroll area so the action
   and the reassurance next to it are always visible. */
.savebar {
    position: sticky; bottom: 0; z-index: 2;
    display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2);
    margin-top: var(--gap); padding: var(--sp-2) 11px;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
    box-shadow: 0 -2px 8px rgba(11, 74, 47, .05);
}
.savebar__note { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: var(--text-xs); color: var(--ink-500); }
.savebar__actions { margin-left: auto; display: flex; gap: 6px; flex: 0 0 auto; }

/* ---- report rows -------------------------------------------------------
   A two-column list rather than a card grid. Fourteen reports as tiles is a
   page of scrolling; as rows it is one screen, and the summary still fits. */
.rlist { display: grid; grid-template-columns: 1fr; gap: var(--gap); }
.rrow {
    display: flex; align-items: center; gap: var(--sp-3); padding: 9px 11px;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
}
.rrow__text { min-width: 0; }
.rrow__text > b { display: block; font-size: var(--text-md); }
.rrow__text > span {
    display: block; font-size: var(--text-xs); color: var(--ink-500);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rrow__actions { margin-left: auto; display: flex; gap: 6px; flex: 0 0 auto; }
@media (min-width: 1240px) { .rlist { grid-template-columns: 1fr 1fr; } }

/* ---- approval progress pips -------------------------------------------
   One dot per required approver, filled as each signs. At three or four
   approvers this is read at a glance where "2/3" has to be parsed. */
.pips { display: inline-flex; align-items: center; gap: 4px; }
.pips > i {
    display: grid; place-items: center; width: 14px; height: 14px; border-radius: 50%;
    background: var(--ink-100); color: var(--ink-400);
}
.pips > i.is-done { background: var(--accent-100); color: var(--brand); }

/* ---- inline table action ----------------------------------------------- */
.act {
    display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
    font-size: var(--text-xs); font-weight: 600; color: var(--brand); text-decoration: none;
}
.act:hover { text-decoration: underline; }
.act + .act { margin-left: var(--sp-2); }

/* ---------------------------------------------------------------- responsive */

@media (min-width: 600px) {
    .form-grid--2 { grid-template-columns: 1fr 1fr; }
    .dl { grid-template-columns: repeat(2, 1fr); }
    .filters { grid-template-columns: repeat(2, 1fr); }
    .content { padding: var(--sp-6) var(--sp-6) var(--sp-12); }
}

@media (min-width: 768px) {
    .search { display: block; }
    .grid--2 { grid-template-columns: repeat(2, 1fr); }
    /* Half-width is the first useful step for a panel: two side by side still
       leaves a readable table. The 8/4 split waits for 1240. */
    .g12 > .col-4, .g12 > .col-6 { grid-column: span 6; }
}

@media (min-width: 992px) {
    .usermenu__name { display: block; }
    .grid--3 { grid-template-columns: repeat(3, 1fr); }
    .grid--sidebar { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); align-items: start; }
    .filters { grid-template-columns: repeat(4, 1fr); }
    .dl { grid-template-columns: repeat(3, 1fr); }
    .content { padding: 12px 16px var(--sp-10); }
}

/* The sidebar pins at 1100px. It used to be 1200px because a 228px rail plus a
   data table left the table too narrow to read at tablet width; the rail is
   184px now, so it earns its place 100px earlier. Below this it still goes
   off-canvas and the content takes the full width. */
@media (min-width: 1100px) {
    .sidebar { transform: translateX(0); }
    .main { margin-left: var(--sidebar-w); }
    .scrim, .sidebar-toggle { display: none; }
}

/* The 8/4 split, and the pipeline's chevrons.

   Both wait until 1240 because the content area is only then wide enough: a
   4-column panel inside a 1100px viewport minus a 184px rail is ~250px, which
   is narrower than the donut plus its key. Below this the flow stacks and drops
   its clip-path - a vertical chevron points nowhere. */
@media (min-width: 1240px) {
    .g12 > .col-4 { grid-column: span 4; }
    .g12 > .col-6 { grid-column: span 6; }
    .g12 > .col-8 { grid-column: span 8; }
}

@media (max-width: 1239px) {
    .flow { flex-direction: column; }
    .flow__stage,
    .flow__stage:first-child,
    .flow__stage:last-child {
        clip-path: none; border-radius: var(--r-sm); padding-left: 11px;
    }
}

/* The KPI row is eight tiles at full width, four on a laptop, two on a phone.
   grid--kpi's own auto-fit rules already handle the existing pages; this is the
   fixed-count variant the dashboard's row uses so the eight stay aligned. */
.grid--kpi8 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gap); }
@media (min-width: 768px)  { .grid--kpi8 { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 1500px) { .grid--kpi8 { grid-template-columns: repeat(8, 1fr); } }

/* Tables become cards on narrow screens, using data-label on each cell. */
@media (max-width: 767px) {
    .table--responsive thead { display: none; }
    .table--responsive tbody tr {
        display: block; border: 1px solid var(--ink-200); border-radius: var(--r-sm);
        margin-bottom: var(--sp-2); padding: 6px; background: var(--surface);
    }
    .table--responsive tbody tr:hover { background: var(--surface); }
    .table--responsive td {
        display: flex; justify-content: space-between; gap: var(--sp-3);
        padding: 5px 6px; border-bottom: 1px dashed var(--ink-100); text-align: right;
    }
    .table--responsive td:last-child { border-bottom: 0; }
    .table--responsive td::before {
        content: attr(data-label); flex: 0 0 42%; text-align: left;
        font-size: var(--text-xs); font-weight: 700; text-transform: uppercase;
        letter-spacing: .05em; color: var(--ink-500);
    }
}

/* SOP content must not be printed. Reports remain printable. */
@media print {
    .sidebar, .topbar, .scrim, .flashes, .page-head__actions, .no-print, .testbar { display: none !important; }
    .main { margin-left: 0; }
    body { background: #fff; }
    .card { border: 1px solid #ccc; box-shadow: none; }
    .viewer { display: none !important; }
}

/* ---- modal ---------------------------------------------------------------
   A native <dialog>, so focus trapping, Escape, and inertness of the page
   behind it are the browser's job rather than ours - there is no modal library
   here and one is not worth carrying for two screens.

   `.modal` was free: nothing in this stylesheet used the name. Checked before
   adding it, which is the rule a `.person` collision taught us the hard way. */
.modal {
    width: min(720px, calc(100vw - 2 * var(--sp-4)));
    max-height: calc(100vh - 2 * var(--sp-6));
    padding: 0;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--surface);
    color: var(--ink-900);
    box-shadow: var(--sh-lg);
    overflow: hidden;
}
.modal::backdrop { background: rgba(11, 40, 28, .44); }

.modal__head {
    display: flex; align-items: center; gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-5);
    border-bottom: 1px solid var(--line-soft);
    background: var(--surface-raised);
}
.modal__head h2 { margin: 0; font-size: var(--text-lg); font-weight: 700; }
.modal__head p { margin: 2px 0 0; font-size: var(--text-xs); color: var(--ink-500); }
.modal__close {
    margin-left: auto; flex: 0 0 auto;
    width: 28px; height: 28px; border: 0; border-radius: var(--r-sm);
    background: none; color: var(--ink-500); font-size: 20px; line-height: 1; cursor: pointer;
}
.modal__close:hover { background: var(--ink-100); color: var(--ink-900); }

/* The only scrolling region, so the head and the footer stay put on a long form. */
.modal__body { padding: var(--sp-5); overflow-y: auto; max-height: calc(100vh - 210px); }
.modal__foot {
    display: flex; align-items: center; gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-5);
    border-top: 1px solid var(--line-soft); background: var(--surface-raised);
}
.modal__foot .btn:first-child { margin-left: auto; }

/* Full-height sheet on a phone: a centred box with margins wastes the space a
   long role list needs. */
@media (max-width: 640px) {
    .modal { width: 100vw; max-width: 100vw; max-height: 100vh; height: 100vh; border-radius: 0; border: 0; }
    .modal__body { max-height: calc(100vh - 128px); }
    .modal__foot { position: sticky; bottom: 0; }
}

/* ---- utilities ---------------------------------------------------------
   Added 2026-10-01 so that `style-src 'unsafe-inline'` could come out of the
   Content-Security-Policy (CWE-693 in the CERT-In VAPT of this portal).

   A style="" attribute is governed by 'unsafe-inline' and nothing else - a nonce
   cannot cover one - so every inline style on an app page had to become either a
   class here or a data-* attribute that app.js applies. These are the former.

   They are intentionally a small, closed set that names the exact declarations
   the pages were already using, not a general utility framework. If you find
   yourself wanting a new one, prefer putting the rule on the component's own
   class: that is how the rest of this stylesheet works, and it is why the design
   could be re-skinned twice without touching markup.

   The `u-` prefix exists because this file's component classes are unprefixed and
   a bare `.inline` or `.dim` would collide with one sooner or later - which has
   already happened once here, with `.person`. */
.u-ml-auto     { margin-left: auto; }
.u-ml-6        { margin-left: 6px; }
.u-mt-gap      { margin-top: var(--gap); }
.u-mb-3        { margin-bottom: var(--sp-3); }
.u-mb-5        { margin-bottom: var(--sp-5); }
.u-my-2-3      { margin: var(--sp-2) 0 var(--sp-3); }
.u-gap-2-mb-4  { gap: var(--sp-2); margin-bottom: 4px; }

.u-grid-1      { grid-template-columns: 1fr; }
.u-grid-2      { grid-template-columns: 1fr 1fr; }

.u-inline      { display: inline; }
.u-nolist      { list-style: none; }
.u-pre         { white-space: pre-wrap; }
.u-upper       { text-transform: uppercase; }
.u-tnum        { font-variant-numeric: tabular-nums; }

.u-dim         { opacity: .62; }
.u-dimmer      { opacity: .55; }
.u-ink-600     { color: var(--ink-600); }
.u-ink-700     { color: var(--ink-700); }
.u-danger      { color: var(--danger); }

.u-minw-0      { min-width: 0; }
.u-minw-104    { min-width: 104px; }
.u-minw-118    { min-width: 118px; }
.u-minw-148    { min-width: 148px; margin-bottom: 6px; }
.u-sq-24       { width: 24px; height: 24px; }

/* Legend swatches on the dashboard's publishing mix. */
.u-dot-brand   { background: var(--brand); }
.u-dot-amber   { background: #D98A1F; }
.u-dot-grey    { background: var(--ink-100); }

/* error.php stands alone - it is served for 403/404/429 and does not load the
   app chrome, so its layout lives here rather than in a component. */
.u-center-page { min-height: 100vh; display: grid; place-items: center; padding: 2rem 1rem; }
.u-w620        { max-width: 620px; width: 100%; }
.u-err-code    { font-size: var(--text-3xl); font-weight: 700; color: var(--brand); margin: 0; }
.u-none        { display: none !important; }
