/* ---- Theme tokens ---------------------------------------------------------
   azam-proto.css carries the light palette; azam-theme-dark.css (the approved
   dark prototype's own override block) flips the --gray / --navy / --white
   scale when the dark theme is on. These are the extra tokens this file needs
   on top of that, so each rule below is written once and works in both. */
:root {
    --app-zebra:            rgba(11, 31, 63, .035);
    --app-row-hover:        rgba(0, 114, 188, .09);
    --app-hairline:         var(--gray-200, #e4e8ee);
    --app-grid-head-bg:     var(--gray-50, #f8fafc);
    --app-modal-bg:         var(--white, #fff);
    --app-modal-scrim:      rgba(11, 31, 63, .45);
    --app-modal-border:     rgba(11, 31, 63, .14);
    --app-ctl-border:       rgba(11, 31, 63, .16);
    --app-ctl-bg:           rgba(11, 31, 63, .04);
    --app-alert-error-bg:   #fdebec;
    --app-alert-error-fg:   #a2141b;
    --app-alert-ok-bg:      #e4f5ee;
    --app-alert-ok-fg:      #12684a;
    --app-action-edit:      #0e6ea8;
    --app-action-view:      #0072bc;
    --app-action-off:       #9a5b06;
    --app-action-delete:    #c01722;
    --app-shadow-lift:      0 10px 24px rgba(11, 31, 63, .16);
    --app-track:            rgba(11, 31, 63, .10);
    --app-help-fg:          #0c5c92;
    --app-grid-head-fg:     #9a6b06;
    --app-subtext-fg:       #4d5766;
    /* KPI / pipeline accents: the darker end is the one that reads on white */
    --kpi-blue-to:  #0e7fc4;
    --kpi-red-to:   #d0121b;
    --kpi-amber-to: #a9640a;
    --kpi-green-to: #0f7d5e;
}
[data-theme="dark"] {
    --app-zebra:            rgba(255, 255, 255, .022);
    --app-row-hover:        rgba(0, 114, 188, .13);
    --app-grid-head-bg:     #0b1d33;
    --app-modal-bg:         linear-gradient(160deg, #102139, #0b1d33);
    --app-modal-scrim:      rgba(4, 12, 24, .72);
    --app-modal-border:     rgba(136, 206, 238, .26);
    --app-ctl-border:       rgba(255, 255, 255, .14);
    --app-ctl-bg:           rgba(255, 255, 255, .05);
    --app-alert-error-bg:   #3a1220;
    --app-alert-error-fg:   #ff8f95;
    --app-alert-ok-bg:      rgba(34, 197, 94, .15);
    --app-alert-ok-fg:      #5ce39b;
    --app-action-edit:      #7bd3ff;
    --app-action-view:      #56c8ff;
    --app-action-off:       #ffb84d;
    --app-action-delete:    #ff8f95;
    --app-shadow-lift:      0 10px 24px rgba(0, 0, 0, .35);
    --app-track:            rgba(255, 255, 255, .09);
    --app-help-fg:          #a9d6f2;
    --app-grid-head-fg:     #d9a441;
    --app-subtext-fg:       #9fb3cc;
    --kpi-blue-to:  #56c8ff;
    --kpi-red-to:   #ff6b72;
    --kpi-amber-to: #ffb84d;
    --kpi-green-to: #55e6b8;
}

/* Azam RMS — minimal additions on top of the approved prototype stylesheet (azam-proto.css).
   Only classes the prototype does NOT define live here. Never redefine prototype components
   (.card, .field, .form-grid, .button, .stat, .badge, .simple-table, .page-header ...). */

/* Nav items for stages not yet implemented — kept fully legible (white), not dimmed */
.sidebar nav button.soon,
.sidebar-bottom button.soon {
    opacity: 1;
    color: #ffffff;
    cursor: default;
}
.sidebar nav button.soon span,
.sidebar-bottom button.soon { color: #ffffff; }
.sidebar nav button.soon svg,
.sidebar-bottom button.soon svg { opacity: .9; }

/* Brand subtitle — Azam red, carrying the masthead accent into the rail */
.sidebar .brand span {
    color: var(--azam-red, #ed1c24);
    opacity: 1;
    font-weight: 900;
    letter-spacing: .1em;
}

/* ---- Collapsible nav groups -----------------------------------------------
   Each section header is a boxed, clickable bar with a caret; its links sit in
   a bordered panel underneath, so the rail reads as grouped rather than as one
   long list. Open/closed state persists per group. */
.sidebar .nav-section { margin-bottom: 6px; }

.sidebar .nav-section > p,
.sidebar .nav-group-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    width: 100%;
    margin: 0;
    padding: .55rem .7rem;
    border: 1px solid rgba(136, 206, 238, .2);
    border-radius: 8px;
    background: rgba(136, 206, 238, .07);
    color: var(--sky-300, #88ceee);
    font: inherit;
    font-size: .64rem;
    font-weight: 900;
    letter-spacing: .12em;
    text-transform: uppercase;
    opacity: 1;
    cursor: pointer;
    text-align: left;
    transition: background-color .15s ease, border-color .15s ease;
}
.sidebar .nav-group-head:hover { background: rgba(136, 206, 238, .14); border-color: rgba(136, 206, 238, .38); }

/* Caret rotates to point down when the group is open */
.sidebar .nav-group-head .caret {
    flex: 0 0 auto;
    transition: transform .18s ease;
    opacity: .8;
}
.sidebar .nav-section.open .nav-group-head .caret { transform: rotate(90deg); }

/* The links panel */
.sidebar .nav-group-body {
    display: grid;
    grid-template-rows: 1fr;
    padding: 4px 0 6px;
    margin: 3px 0 0;
    border: 1px solid rgba(255, 255, 255, .07);
    border-top: 0;
    border-radius: 0 0 8px 8px;
    background: rgba(0, 0, 0, .16);
}
.sidebar .nav-section:not(.open) .nav-group-body { display: none; }
.sidebar .nav-group-body button { padding-left: 14px; }

/* Only the link list scrolls — the brand and the sign-out block stay put — and
   its scrollbar is hidden, because it cut into the 236px rail and read as a
   seam. The sidebar itself keeps overflow visible so the collapse toggle can
   sit on its outer edge. */
.sidebar { overflow: visible; }
.sidebar nav {
    flex: 1 1 auto;
    min-height: 0;
    /* .sidebar nav is display:grid in the prototype. Without this the rows
       stretch to fill the rail and closing every group leaves big even gaps
       between the group heads. */
    align-content: start;
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: none;
    -ms-overflow-style: none;
}
.sidebar nav::-webkit-scrollbar { width: 0; height: 0; }

/* The active item keeps the approved prototype treatment (red rail + glow).
   Only the left offset is corrected, because the group panel indents the
   buttons and the prototype's -14px would put the rail outside the panel. */
.sidebar .nav-group-body button.active::before { left: 0; }

/* Hover echo for non-active items */
.sidebar nav button:not(.active):hover { border-radius: 7px; background: rgba(255, 255, 255, .05); }

/* Active nav item.
   Light theme: red base — brand-red fill + red border, white icon.
   Dark theme: matches the source prototype (UI_Framework_viaframe/
   azam-rms-workflow-prototype-dark.html) — translucent blue→indigo fill,
   faint sky border, sky-blue leading icon, white bold text. The red accent
   is the 3px left rail (::before) the prototype already defines. */
.sidebar nav button.active {
    background: linear-gradient(90deg, rgba(237, 28, 36, .55), rgba(157, 53, 48, .40));
    border: 1px solid rgba(237, 28, 36, .55);
    color: #fff;
}
.sidebar nav button.active svg:first-child { color: #fff; }
[data-theme="dark"] .sidebar nav button.active {
    /* Translucent red -> dark-blue gradient (navy shows through). Softer red on
       the left, blending to dark blue. Blue border, not red. */
    background: linear-gradient(90deg, rgba(237, 28, 36, .34) 0%, rgba(237, 28, 36, .16) 30%, rgba(39, 54, 145, .55) 100%);
    border: 1px solid var(--azam-red, #ed1c24);
    color: #fff;
}
/* Keep the red left rail but tame its glow so it doesn't read as a red border
   around the button. */
[data-theme="dark"] .sidebar nav button.active::before { box-shadow: 0 0 6px rgba(237, 28, 36, .4); }
[data-theme="dark"] .sidebar nav button.active svg:first-child { color: var(--sky-300, #88ceee); }

/* Leaf nav links carry a trailing chevron (.nav-arrow) that reads like an
   "expandable" affordance — misleading on a direct link such as Network
   overview. Group headers keep their own .caret; only the leaf chevron goes. */
.sidebar nav .nav-arrow { display: none; }
/* Draw a uniform chevron on the active item in CSS, so it shows on EVERY active
   link (not every button carries the .nav-arrow markup). Expanded rail only. */
body:not(.nav-collapsed) .sidebar nav button.active::after {
    content: "";
    margin-left: auto;
    flex: 0 0 auto;
    width: 6px; height: 6px;
    border-right: 2px solid #9bb3d2;
    border-top: 2px solid #9bb3d2;
    transform: rotate(45deg);
}

/* Collapsed rail: headers and panels give way to plain icon buttons */
body.nav-collapsed .sidebar .nav-group-head { display: none; }
body.nav-collapsed .sidebar .nav-section .nav-group-body,
body.nav-collapsed .sidebar .nav-section:not(.open) .nav-group-body { display: block; border: 0; background: none; padding: 2px 0; }
body.nav-collapsed .sidebar .nav-group-body button { padding-left: 12px; }

/* ---- Flash / validation messages -----------------------------------------
   Loud enough to be noticed: coloured rail down the left edge, a matching icon
   chip, a bold heading line and a lift shadow. */
/* `.alert { display:flex }` beats the browser's [hidden]{display:none}, so an
   alert with the `hidden` attribute (e.g. the modal's #centre-form-error, shown
   only when there are validation errors) would otherwise render as an empty red
   bar. Restore `hidden` for alerts. */
.alert[hidden] { display: none !important; }
.alert {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: .7rem;
    border-radius: 10px;
    padding: .85rem 1rem .85rem 1.15rem;
    margin-bottom: 16px;
    font-weight: 700;
    font-size: .85rem;
    line-height: 1.45;
    overflow: hidden;
    box-shadow: var(--app-shadow-lift);
    animation: rms-alert-in .3s ease-out both;
}
.alert::before {                       /* accent rail */
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 4px;
    background: currentColor;
}
/* Leading warning glyph, drawn in CSS so no markup changes at each call site */
.alert::after {
    content: "⚠";
    order: -1;
    flex: 0 0 auto;
    margin-top: -.05rem;
    font-size: .95rem;
    line-height: 1.4;
}
.alert-ok::after { content: "✓"; }
.alert > div { color: inherit; }

/* Approved Azam red on a deep maroon fill — the same treatment as the
   duplicate-serial validation message on the intake screen. */
.alert-error { background: var(--app-alert-error-bg); color: var(--app-alert-error-fg); border: 1px solid rgba(237, 28, 36, .55); }
.alert-ok    { background: var(--app-alert-ok-bg); color: var(--app-alert-ok-fg); border: 1px solid rgba(34, 197, 94, .42); }
/* Something to weigh rather than an error: a repeat visit, a flag for review. */
.alert-warn  { background: rgba(247, 144, 9, .12); color: #8a5200; border: 1px solid rgba(247, 144, 9, .55); }
:root[data-theme="dark"] .alert-warn { color: #f5b454; }

/* Dismiss control (optional — rendered by views that add it) */
.alert .alert-close {
    margin-left: auto;
    flex: 0 0 auto;
    border: 0;
    background: transparent;
    color: inherit;
    font-size: 1rem;
    line-height: 1;
    opacity: .65;
    cursor: pointer;
}
.alert .alert-close:hover { opacity: 1; }
/* One compact row: icon, message, close - never a second line just for the close button. */
.alert { flex-wrap: nowrap; align-items: center; padding-top: .6rem; padding-bottom: .6rem; }
.alert > div { flex: 1 1 auto; min-width: 0; }
.alert .alert-close { order: 2; width: auto; height: auto; padding: 0 .2rem; font-size: 1.15rem; }
/* Report charts: a row of chart cards above the table, one column on a phone. */
.report-charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-bottom: 20px; }
.chart-empty { padding: 0 18px 18px; color: var(--gray-500); }
.chart-legend { display: flex; flex-wrap: wrap; gap: 16px; padding: 6px 18px 16px; font-size: 11px; color: var(--gray-500); }
.chart-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; }
.chart-legend i.held, .hbar.held { background: var(--green-600); }
.chart-legend i.rework, .hbar.rework { background: var(--gold-500); }
/* Horizontal bars: name, bar, value. */
.hbar-chart { display: grid; gap: 10px; padding: 4px 18px 8px; }
.hbar-row { display: grid; grid-template-columns: minmax(80px, 32%) 1fr 28px; align-items: center; gap: 10px; }
.hbar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; }
.hbar-track { display: flex; height: 12px; border-radius: 6px; overflow: hidden; background: color-mix(in srgb, var(--gray-500) 18%, transparent); }
.hbar { display: block; height: 100%; }
.hbar-value { text-align: right; }
/* Money needs more room than a count. */
.hbar-chart.wide-value .hbar-row { grid-template-columns: minmax(80px, 32%) 1fr 56px; }
/* Trend lines: percentages over months; month labels line up under each point. */
.trend-chart { padding: 4px 18px 0; }
.trend-svg { display: block; width: 100%; height: auto; }
.trend-svg .grid { stroke: var(--gray-200); stroke-dasharray: 3 5; }
.trend-svg .axis { fill: var(--gray-500); font-size: 12px; }
.trend-svg path { fill: none; stroke-width: 3; stroke-linejoin: round; stroke-linecap: round; }
.trend-svg path.ftf { stroke: var(--green-600); }
.trend-svg path.rework { stroke: var(--gold-500); }
.trend-svg circle.ftf { fill: var(--green-600); }
.trend-svg circle.rework { fill: var(--gold-500); }
.trend-x { display: grid; padding-left: 6.667%; text-align: center; font-size: 11px; color: var(--gray-500); }
.trend-x b { display: block; font-size: 10px; font-weight: 400; }

/* The reports list: one tile per report. */
.report-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; }
.report-tile { display: block; padding: 20px; color: inherit; text-decoration: none; transition: transform .15s ease, box-shadow .15s ease; }
.report-tile:hover { transform: translateY(-2px); box-shadow: var(--app-shadow-lift, var(--shadow-lift)); }
.report-tile h2 { margin-bottom: 6px; }
.report-tile p { color: var(--gray-500); }
/* The SLA target as a dashed line on a trend chart. */
.trend-svg .target { stroke: var(--red-600); stroke-dasharray: 6 5; stroke-width: 2; }
.chart-legend i.target { background: var(--red-600); height: 3px; border-radius: 0; vertical-align: 3px; }

/* Report filters: month, region and centre in a row, wrapping on a phone. */
.report-filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.report-filters .input { flex: 0 1 220px; min-width: 160px; }

/* Granting a late-closing exception on the Commission page: reason, note, button. */
.grant-exception { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 6px; }
.grant-exception .input { flex: 1 1 160px; min-width: 140px; }

/* Settling a review on the ticket page: a note, then clear or uphold, on one line where it fits. */
.review-flag { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: -2px 0 14px; }
.review-flag .input { flex: 1 1 220px; }
.alert.alert-leaving { opacity: 0; transform: translateY(-6px); transition: opacity .35s ease, transform .35s ease; }

@keyframes rms-alert-in {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) { .alert { animation: none; } }

/* On the login card the alert sits directly under the intro copy, above the
   Google button, and needs a little breathing room from both. */
.login-card .alert { margin: 18px 0 4px; font-size: .82rem; }

/* Form action row (prototype styles the fields, not the button row) */
.form-actions { margin-top: 18px; display: flex; gap: 10px; flex-wrap: wrap; }

/* Google Map inside the prototype's map card.
   When a Maps key is configured, the real map replaces the stylized placeholder;
   the legend (.map-key) stays on top. */
#centres-map { position: absolute; inset: 0; border-radius: inherit; z-index: 0; }
/* Separate the live map from the surrounding card */
.map-canvas.has-gmap {
    border: 1px solid rgba(136, 206, 238, .28);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .35);
    overflow: hidden;
}
.map-canvas.has-gmap > .map-grid,
.map-canvas.has-gmap > .land-shape,
.map-canvas.has-gmap > .map-label,
.map-canvas.has-gmap > svg.pin { display: none; }
.map-canvas.has-gmap > .map-key { z-index: 2; }

/* Real form controls inside the prototype's display-only ".input" wrapper.
   The wrapper keeps the approved border/background; the control is transparent. */
.input input,
.input select,
.input textarea {
    flex: 1 1 auto;
    min-width: 0;
    background: transparent;
    border: 0;
    outline: none;
    color: inherit;
    font: inherit;
    padding: 0;
    appearance: none;
    -webkit-appearance: none;
}
.input input::placeholder,
.input textarea::placeholder { color: currentColor; opacity: .45; }
.input select option { background: var(--white, #fff); color: var(--gray-900, #1a2333); }
.input input[type="date"]::-webkit-calendar-picker-indicator { opacity: .5; cursor: pointer; }
[data-theme="dark"] .input input[type="date"]::-webkit-calendar-picker-indicator { filter: invert(1); }

/* Real textarea inside the prototype's display-only ".textarea" wrapper */
.textarea textarea {
    width: 100%;
    min-height: 66px;
    resize: vertical;
    background: transparent;
    border: 0;
    outline: none;
    color: inherit;
    font: inherit;
    padding: 0;
}
.textarea textarea::placeholder { color: currentColor; opacity: .45; }

/* Outcome selector buttons are interactive */
.outcomes button { cursor: pointer; }

/* Framework error page */
.text-danger { color: var(--azam-red, #ed1c24); }

/* Per-centre map (Maps Embed API — free, one place per iframe) */
.centre-map summary {
    cursor: pointer;
    font-weight: 800;
    font-size: .78rem;
    color: var(--azam-cyan, #88ceee);
    padding: .35rem 0;
    list-style: none;
}
.centre-map summary::-webkit-details-marker { display: none; }
.centre-map summary::before { content: "▸ "; }
.centre-map[open] summary::before { content: "▾ "; }
.centre-map iframe,
.centre-map .centre-map-canvas {
    width: 100%;
    height: 300px;
    border: 1px solid rgba(136, 206, 238, .28);
    border-radius: 10px;
    margin-top: .5rem;
    background: var(--gray-50, #f8fafc);
}
.map-row > td { padding-top: 0; }

/* Tabs (settings and any future tabbed screen) — underline style: the label
   itself carries the state, marked by a solid Azam-blue rule beneath it. */
.tab-strip {
    display: flex;
    gap: .35rem;
    flex-wrap: wrap;
    align-items: center;
    padding: 6px;
    border: 1px solid rgba(255, 255, 255, .08);
    border-radius: 12px;
    background: rgba(13, 29, 51, .48);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    box-shadow: 0 6px 20px rgba(0, 0, 0, .18);
    margin-bottom: 18px;
}
[data-theme="light"] .tab-strip {
    background: rgba(255, 255, 255, .55);
    border-color: rgba(11, 31, 63, .08);
    box-shadow: 0 6px 20px rgba(11, 31, 63, .06);
}
/* An action on the tab row (Save settings) sits at its right-hand end. */
.tab-strip .tab-strip-action { margin-left: auto; display: flex; align-items: center; }
.tab-strip .tab {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .5rem .95rem;
    border: 1px solid transparent;
    border-radius: 9px;
    background: transparent;
    color: inherit;
    font: inherit;
    font-weight: 800;
    font-size: .86rem;
    cursor: pointer;
    opacity: .72;
    transition: background-color .15s ease, border-color .15s ease, opacity .15s ease, color .15s ease;
}
.tab-strip .tab:hover { opacity: 1; background: rgba(136, 206, 238, .10); }
/* Active tab reads as a filled pill (segmented-control style) so it is clearly
   the selected tab, not just a bold label. */
.tab-strip .tab.active {
    opacity: 1;
    color: #fff;
    background: rgba(21, 149, 230, .22);
    border-color: rgba(21, 149, 230, .55);
    box-shadow: inset 0 0 0 1px rgba(21, 149, 230, .15);
}
[data-theme="light"] .tab-strip .tab:hover { background: rgba(0, 114, 188, .07); }
[data-theme="light"] .tab-strip .tab.active {
    color: var(--azam-blue-dark, #273691);
    background: rgba(0, 114, 188, .10);
    border-color: rgba(0, 114, 188, .35);
}
.tab-strip .tab em { font-style: normal; }

.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* Role checkbox grid in the create-user modal */
.role-picker { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 6px 14px; margin-top: 6px; }
.role-option { display: flex; align-items: center; gap: 8px; font-size: .85rem; cursor: pointer; }
.role-option input { width: 15px; height: 15px; flex: 0 0 auto; }
/* Two or three short choices side by side in a table cell, e.g. Pass / Fail. */
.role-picker.inline { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 0; }

/* Helper text under a settings field */
.field-help { display: block; margin-top: .25rem; font-size: .72rem; opacity: .7; }

/* ---- Content measure ------------------------------------------------------
   On wide monitors the prototype's full-bleed main stretches single inputs to
   1500px+, which reads as sparse at the top and cramped at the bottom. Cap the
   measure and centre it; below the cap nothing changes. */
main { width: 100%; max-width: 1660px; margin-left: 0; margin-right: auto; }

/* Glass treatment for the page title strip so it reads cleanly over the
   particle background. Theme-aware translucent panel + blur. */
.page-header {
    background: rgba(13, 29, 51, .48);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border: 1px solid rgba(255, 255, 255, .08);
    border-radius: 12px;
    padding: 14px 18px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, .18);
}
[data-theme="light"] .page-header {
    background: rgba(255, 255, 255, .55);
    border-color: rgba(11, 31, 63, .08);
    box-shadow: 0 6px 20px rgba(11, 31, 63, .06);
}

/* Settings: three columns on wide screens so related keys sit together instead
   of two very long rows, and give each field room to breathe. */
@media (min-width: 1360px) {
    .tab-panel .form-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.tab-panel .form-grid { row-gap: 18px; }

/* Small layout utilities (replace inline style attributes) */
.flush { margin: 0; }
.login-access.full-width { grid-column: 1 / -1; }
.form-grid .field-wide { grid-column: 1 / -1; }

/* ---- Login screen corrections ---------------------------------------------
   The prototype sets .google-login b to 12px, which reads as small next to the
   14px form labels around it. Bring it up to the same weight as the fields. */
.login-card .google-login b { font-size: .95rem; letter-spacing: .01em; }
.login-card .google-login .google-g { font-size: 1.05rem; }

/* The help line is guidance, not a warning — give it the Azam blue treatment
   so it is legible and clearly distinct from the red error alert above it. */
.login-card .login-help {
    color: var(--app-help-fg);
    border-color: rgba(0, 114, 188, .42);
    background: rgba(0, 114, 188, .12);
    font-size: .76rem;
}
.login-card .login-help svg { color: var(--app-help-fg); opacity: .85; }

/* ---- KPI stat cards -------------------------------------------------------
   Gradient accent bar across the top and the value tinted to match, so each KPI
   is identifiable at a glance. Colours stay on the Azam palette. */
.stats-grid .stat {
    position: relative;
    overflow: hidden;
    border-top: 0;                 /* replaced by the gradient bar below */
    transition: transform .15s ease, box-shadow .15s ease;
}
.stats-grid .stat::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 4px;
    background: linear-gradient(90deg, var(--kpi-from), var(--kpi-to));
}
.stats-grid .stat:hover { transform: translateY(-2px); box-shadow: var(--app-shadow-lift); }

/* Value tinted to the accent */
.stats-grid .stat strong { color: var(--kpi-to); }

/* Per-card accents */
.stats-grid .stat.blue  { --kpi-from: #1595e6; --kpi-to: var(--kpi-blue-to); }
.stats-grid .stat.red   { --kpi-from: #ed1c24; --kpi-to: var(--kpi-red-to); }
.stats-grid .stat.amber { --kpi-from: #d98014; --kpi-to: var(--kpi-amber-to); }
.stats-grid .stat.navy  { --kpi-from: #17a67f; --kpi-to: var(--kpi-green-to); }

/* Icon chip picks up the accent too */
.stats-grid .stat .stat-icon { color: var(--kpi-to); }

/* Keep the "not configured" placeholder muted rather than shouting in accent colour */
.stats-grid .stat strong:only-child,
.stats-grid .stat strong.muted { color: inherit; }

/* ---- Workflow pipeline card ----------------------------------------------
   Icons replace the stage labels on narrow screens so text never wraps. */

/* Let the card distribute its content instead of leaving dead space below */
.overview-grid > .card { display: flex; flex-direction: column; }
.overview-grid > .card .pipeline { flex: 1 1 auto; align-items: stretch; }
.overview-grid > .card .mini-metrics { margin-top: auto; }

/* Stage tile: label, value and a proportional volume bar, with a tone accent on top.
   --pct is the stage's share of the busiest stage and is set per tile from the data. */
.pipe-step {
    position: relative;
    /* Equal share of the row regardless of label length, so "Awaiting parts"
       does not push a wider tile than "Received". */
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .25rem;
    padding: .85rem .5rem 1.1rem;
    overflow: hidden;
    transition: transform .15s ease, box-shadow .15s ease;
}
.pipe-step::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: var(--tone, #1595e6);
    opacity: .9;
}
.pipe-step:hover { transform: translateY(-2px); box-shadow: var(--app-shadow-lift); }

.pipe-step.blue  { --tone: var(--kpi-blue-to); }
.pipe-step.amber { --tone: var(--kpi-amber-to); }
.pipe-step.green { --tone: var(--kpi-green-to); }

.pipe-step .step-icon { display: none; line-height: 0; color: var(--tone, #88ceee); }
/* Labels never wrap; they shrink slightly instead */
.pipe-step .step-label { white-space: nowrap; font-size: .6rem; }

/* Volume bar: width is the stage's share of the busiest stage */
.pipe-step .step-bar {
    position: absolute;
    left: 10%;
    right: 10%;
    bottom: .5rem;
    height: 3px;
    border-radius: 999px;
    background: var(--app-track);
    overflow: hidden;
}
.pipe-step .step-bar::after {
    content: "";
    display: block;
    height: 100%;
    width: var(--pct, 0%);
    background: var(--tone, #1595e6);
    border-radius: inherit;
    transition: width .6s ease;
}

/* Connector between steps: a drawn track with an arrow head, so the stages read
   as one flowing chain rather than six tiles with loose chevrons between them.
   The <svg> from the markup is hidden and replaced by this element's own art. */
.pipeline > svg {
    align-self: center;
    flex: 0 0 auto;
    width: 26px;
    height: 12px;
    position: relative;
    overflow: visible;
    /* The source chevron path is suppressed; the rail below is the visible mark */
    color: transparent;
}
.pipeline > svg::before {              /* the rail */
    content: "";
    position: absolute;
    top: 50%;
    left: 0;
    width: 100%;
    height: 2px;
    transform: translateY(-50%);
    border-radius: 999px;
    background: linear-gradient(90deg, rgba(136, 206, 238, .18), var(--sky-300, #88ceee));
}
.pipeline > svg::after {               /* the arrow head */
    content: "";
    position: absolute;
    top: 50%;
    right: -1px;
    width: 7px;
    height: 7px;
    transform: translateY(-50%) rotate(45deg);
    border-top: 2px solid var(--sky-300, #88ceee);
    border-right: 2px solid var(--sky-300, #88ceee);
    border-radius: 1px;
}

/* Bolder, larger stage counts */
.pipeline .pipe-step strong { font-weight: 900; font-size: 1.6rem; letter-spacing: -.01em; }
.mini-metrics b { font-weight: 900; }
.stat strong { font-weight: 900; }

/* Small cards only: swap the label for a larger icon. Normal/large screens keep text.
   Keyed to the CARD's own width (container query) with a viewport fallback. */
.overview-grid > .card { container-type: inline-size; }

@container (max-width: 620px) {
    .pipe-step .step-label { display: none; }
    .pipe-step .step-icon { display: block; }
    .pipe-step .step-icon svg { width: 30px; height: 30px; }
    .pipeline .pipe-step strong { font-size: 1.5rem; }
}

/* Fallback for browsers without container queries */
@supports not (container-type: inline-size) {
    @media (max-width: 900px) {
        .pipe-step .step-label { display: none; }
        .pipe-step .step-icon { display: block; }
        .pipe-step .step-icon svg { width: 30px; height: 30px; }
    }
}

/* Chevrons pulse along the pipeline, suggesting flow between stages */
.pipeline > svg { animation: rms-flow 2.4s ease-in-out infinite; }
.pipeline > svg:nth-of-type(1) { animation-delay: 0s; }
.pipeline > svg:nth-of-type(2) { animation-delay: .18s; }
.pipeline > svg:nth-of-type(3) { animation-delay: .36s; }
.pipeline > svg:nth-of-type(4) { animation-delay: .54s; }
.pipeline > svg:nth-of-type(5) { animation-delay: .72s; }
@keyframes rms-flow {
    0%, 100% { opacity: .35; transform: translateX(0); }
    50%      { opacity: 1;   transform: translateX(3px); }
}

/* Stage counts count-up feel: fade/rise in on load */
.pipeline .pipe-step { animation: rms-step-in .45s ease-out both; }
.pipeline .pipe-step:nth-of-type(1) { animation-delay: .02s; }
.pipeline .pipe-step:nth-of-type(2) { animation-delay: .08s; }
.pipeline .pipe-step:nth-of-type(3) { animation-delay: .14s; }
.pipeline .pipe-step:nth-of-type(4) { animation-delay: .20s; }
.pipeline .pipe-step:nth-of-type(5) { animation-delay: .26s; }
.pipeline .pipe-step:nth-of-type(6) { animation-delay: .32s; }
@keyframes rms-step-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .pipeline > svg,
    .pipeline .pipe-step { animation: none; }
}

/* ---- Click / press feedback ----------------------------------------------
   Subtle press animation on interactive elements, plus a ripple on buttons.
   Respects prefers-reduced-motion. */
.button,
.text-button,
.icon-button,
.sidebar nav button,
.sidebar-bottom button,
.outcomes button,
.top-create {
    position: relative;
    overflow: hidden;
    transition: transform .12s ease, filter .12s ease, box-shadow .12s ease;
    -webkit-tap-highlight-color: transparent;
}

.button:hover,
.outcomes button:hover,
.top-create:hover { filter: brightness(1.08); }

.button:active,
.text-button:active,
.icon-button:active,
.sidebar nav button:active,
.sidebar-bottom button:active,
.outcomes button:active,
.top-create:active {
    transform: scale(.97);
    filter: brightness(.94);
}

/* Keyboard focus stays visible */
.button:focus-visible,
.outcomes button:focus-visible,
.sidebar nav button:focus-visible,
.top-create:focus-visible {
    outline: 2px solid var(--azam-cyan, #88ceee);
    outline-offset: 2px;
}

/* Ripple emitted from the click point (span injected by script) */
.rms-ripple {
    position: absolute;
    border-radius: 50%;
    transform: scale(0);
    background: currentColor;
    opacity: .28;
    pointer-events: none;
    animation: rms-ripple-out .55s ease-out forwards;
}
@keyframes rms-ripple-out {
    to { transform: scale(2.4); opacity: 0; }
}

/* Selecting a diagnosis outcome pops the card briefly */
.outcomes button.selected { animation: rms-pop .25s ease-out; }
@keyframes rms-pop {
    0%   { transform: scale(1); }
    45%  { transform: scale(1.03); }
    100% { transform: scale(1); }
}

/* Row press feedback */
.simple-table .table-row { transition: background-color .15s ease, transform .12s ease; }
.simple-table .table-row:active { transform: scale(.995); }

@media (prefers-reduced-motion: reduce) {
    .button, .text-button, .icon-button, .sidebar nav button, .sidebar-bottom button,
    .outcomes button, .top-create, .simple-table .table-row { transition: none; }
    .rms-ripple { display: none; }
    .outcomes button.selected { animation: none; }
}

/* ---- Data grid ------------------------------------------------------------
   Register/master screens: raised card surface, sticky uppercase header, zebra
   rows, hover highlight and row actions. Palette is the approved Azam one
   (navy surfaces, sky-300 headings, azam-red destructive). */
.grid-card { padding: 0; overflow: hidden; }
.grid-card > .card-head {
    padding: 18px 20px;
    border-bottom: 1px solid rgba(136, 206, 238, .16);
    background: linear-gradient(180deg, rgba(136, 206, 238, .07), transparent);
}

.grid-wrap { overflow-x: auto; }

/* Only the repair centre register carries class="data-grid"; every other register sets the
   data-grid ATTRIBUTE alone (it is what the sort/search script hooks). The class-only rules
   below therefore never reached those tables, which is why one screen looked finished and the
   rest did not. Match either form. */
:is(.data-grid, table[data-grid]) { width: 100%; border-collapse: separate; border-spacing: 0; }

:is(.data-grid, table[data-grid]) th {
    position: sticky;
    top: 0;
    z-index: 1;
    padding: 11px 16px;
    text-align: left;
    font-size: .66rem;
    font-weight: 900;
    letter-spacing: .09em;
    text-transform: uppercase;
    white-space: nowrap;
    /* Azam's gold accent. Blue headings competed with the blue action buttons; gold is used
       nowhere else in the table, so the header row reads as its own band. */
    color: var(--app-grid-head-fg);
    background: var(--app-grid-head-bg);
    border-bottom: 1px solid var(--app-hairline);
}
:is(.data-grid, table[data-grid]) td {
    padding: 13px 16px;
    font-size: .82rem;
    vertical-align: middle;
    border-bottom: 1px solid var(--app-hairline);
    background: transparent;
}
:is(.data-grid, table[data-grid]) td small { display: block; opacity: .62; font-size: .72rem; }

/* Zebra + hover give the rows physical separation */
:is(.data-grid, table[data-grid]) tbody tr:nth-child(2n) td { background: var(--app-zebra); }
:is(.data-grid, table[data-grid]) tbody tr:hover td { background: var(--app-row-hover); }
:is(.data-grid, table[data-grid]) tbody tr:last-child td { border-bottom: 0; }
:is(.data-grid, table[data-grid]) tbody tr { transition: background-color .15s ease; }

.grid-empty { padding: 34px 20px; text-align: center; opacity: .72; }

/* Row action pills */
.row-actions { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap; }

/* Clickable status pill (Active <-> Deactivated) — looks like the badge, acts like a button. */
button.status-toggle { -webkit-appearance: none; appearance: none; border: 0; cursor: pointer; font: inherit; }
button.status-toggle:hover { filter: brightness(1.12); }
button.status-toggle:focus-visible { outline: 2px solid var(--azam-blue, #0072bc); outline-offset: 2px; }

/* Inline checkbox control used in row actions (e.g. Google sign-in). */
.check-inline { display: inline-flex; align-items: center; gap: .35rem; cursor: pointer; white-space: nowrap; padding: .3rem .5rem; }
.check-inline input { cursor: pointer; margin: 0; }

/* Reusable grid toolbar (injected search box) + sortable headers. */
.grid-toolbar { display: flex; justify-content: flex-end; margin-bottom: .6rem; }
th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
th.sortable::after { content: "\2195"; opacity: .35; margin-left: .35rem; font-size: .82em; }
th.sortable[data-sort="asc"]::after { content: "\2191"; opacity: .9; }
th.sortable[data-sort="desc"]::after { content: "\2193"; opacity: .9; }

/* Users grid search box in the card header. */
.card-head-actions { display: flex; align-items: center; gap: .6rem; }
.grid-search { min-width: 220px; padding: .5rem .75rem; border-radius: 8px;
    border: 1px solid var(--gray-300, #c9cfd8); background: var(--white, #fff); color: inherit; font: inherit; }
/* A filter dropdown beside a grid search box, sized to sit on the same line. */
.grid-filter { width: 220px; flex: none; }
.grid-filter .rms-select-trigger { min-height: 38px; }
.grid-search:focus { outline: none; border-color: var(--azam-blue, #0072bc); box-shadow: 0 0 0 3px #0072bc22; }

/* Icon-only action button (e.g. change password) in table rows. */
.icon-button { display: inline-flex; align-items: center; justify-content: center; padding: .4rem .5rem; line-height: 0; }

/* Accent the subject name in a modal title, e.g. "Edit user — <name>". */
.modal-title-accent { color: var(--azam-blue, #0072bc); }
:root[data-theme="dark"] .modal-title-accent { color: #5ab0f0; }

/* Settings toggle switch (e.g. Use TLS). */
.setting-toggle { display: inline-flex; align-items: center; gap: .55rem; cursor: pointer; }
.setting-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.setting-track { width: 40px; height: 22px; border-radius: 999px; background: rgba(128, 128, 128, .45);
    position: relative; transition: background .15s ease; flex: none; }
.setting-track::after { content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px;
    border-radius: 50%; background: #fff; transition: transform .15s ease; box-shadow: 0 1px 2px #0006; }
.setting-toggle input:checked + .setting-track { background: var(--green-600, #1e9e6a); }
.setting-toggle input:checked + .setting-track::after { transform: translateX(18px); }
.setting-toggle input:focus-visible + .setting-track { outline: 2px solid var(--azam-blue, #0072bc); outline-offset: 2px; }
.setting-state { font-size: .85rem; opacity: .85; }

/* Collapsible "Stored secrets" section. */
.secrets-details > summary { cursor: pointer; font-weight: 600; list-style: none; padding: .2rem 0; }
.secrets-details > summary::-webkit-details-marker { display: none; }
.secrets-details > summary::before { content: "\25B8"; opacity: .6; margin-right: .45rem; }
.secrets-details[open] > summary::before { content: "\25BE"; }
.secrets-details[open] > .grid-wrap { margin-top: .6rem; }

/* Modal form fields stack cleanly: label, full-width input, helper text below. */
.rms-modal .field { display: flex; flex-direction: column; gap: .3rem; align-items: stretch; }
.rms-modal .field small { display: block; opacity: .7; }

/* Give modal inputs/selects the same tidy field look as the rest of the app (light theme base). */
.rms-modal .field > input,
.rms-modal .field > select,
.rms-modal .field > textarea {
    width: 100%;
    padding: .55rem .7rem;
    border-radius: 8px;
    border: 1px solid var(--gray-300, #c9cfd8);
    background: var(--white, #fff);
    color: var(--gray-900, #1a2333);
    font: inherit;
}
.rms-modal .field > input:focus,
.rms-modal .field > select:focus,
.rms-modal .field > textarea:focus {
    outline: none;
    border-color: var(--azam-blue, #0072bc);
    box-shadow: 0 0 0 3px #0072bc22;
}
/* Dark theme field surface. */
:root[data-theme="dark"] .rms-modal .field > input,
:root[data-theme="dark"] .rms-modal .field > select,
:root[data-theme="dark"] .rms-modal .field > textarea {
    background: rgba(255, 255, 255, .04);
    border-color: rgba(255, 255, 255, .16);
    color: #eef6ff;
}
/* Native <select> option popup: force readable colours in dark theme
   (a light option colour on the browser's white popup is invisible). */
:root[data-theme="dark"] select option {
    background: #16233c;
    color: #eef6ff;
}
/* Stop Chrome's autofill from painting inputs an ugly brown — force the theme colours. */
.rms-modal .field > input:-webkit-autofill,
.rms-modal .field > input:-webkit-autofill:hover,
.rms-modal .field > input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--gray-900, #1a2333);
    -webkit-box-shadow: 0 0 0 1000px var(--white, #fff) inset;
    caret-color: var(--gray-900, #1a2333);
}
:root[data-theme="dark"] .rms-modal .field > input:-webkit-autofill,
:root[data-theme="dark"] .rms-modal .field > input:-webkit-autofill:hover,
:root[data-theme="dark"] .rms-modal .field > input:-webkit-autofill:focus {
    -webkit-text-fill-color: #eef6ff;
    -webkit-box-shadow: 0 0 0 1000px #16233c inset;
    caret-color: #eef6ff;
}

/* Fault taxonomy tree (Group -> Category -> Fault) on the Fault master screen. */
.fault-tree { display: flex; flex-direction: column; gap: .5rem; }
.tree-node > summary { cursor: pointer; list-style: none; display: flex; align-items: center; gap: .5rem;
    padding: .5rem .6rem; border-radius: 8px; }
.tree-node > summary::-webkit-details-marker { display: none; }
.tree-node > summary::before { content: "\25B8"; opacity: .8; transition: transform .15s ease; }
.tree-node[open] > summary::before { transform: rotate(90deg); }
.tree-node > summary:hover { background: rgba(128, 128, 128, .14); }
.tree-group { border: 1px solid rgba(128, 128, 128, .30); border-radius: 10px; padding: .25rem; }
/* Indent guide lines give the levels a real tree feel. */
.tree-cat { margin-left: 1.25rem; border-left: 2px solid rgba(128, 128, 128, .30); padding-left: .55rem; }
.tree-leaves { list-style: none; margin: .1rem 0 .45rem 2.4rem; padding-left: .75rem; display: flex;
    flex-direction: column; gap: .12rem; border-left: 2px solid rgba(128, 128, 128, .26); }
.tree-leaves li { display: flex; align-items: center; gap: .55rem; padding: .3rem .45rem; border-radius: 6px; }
.tree-leaves li::before { content: ""; width: .7rem; height: 1px; background: rgba(128, 128, 128, .4);
    margin-left: -.75rem; flex: none; }
.tree-leaves li:hover { background: rgba(128, 128, 128, .12); }
.tree-leaves li.is-inactive { opacity: .55; }
/* Readable secondary text (was too faint). */
.tree-sw { opacity: .8; font-style: italic; }
.tree-count { margin-left: auto; opacity: .9; font-size: .78rem; white-space: nowrap; }
.tree-code { font-variant-numeric: tabular-nums; letter-spacing: .01em; font-size: .78rem; opacity: .95;
    min-width: 66px; }
.tree-empty { margin: .1rem 0 .45rem 1.9rem; opacity: .7; font-size: .82rem; }

/* Sidebar nav must scroll (min-height:0 lets the flex item shrink) so the Master group stays
   reachable and Help centre / Sign out don't crowd it. */
.sidebar nav { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

/* Users header + search adapt on small screens. */
@media (max-width: 640px) {
    .card-head-actions { flex-wrap: wrap; width: 100%; }
    .grid-search { flex: 1 1 100%; min-width: 0; }
    .grid-filter { flex: 1 1 100%; width: auto; }
}

/* Hint shown over the placeholder map when the Maps JS key isn't loaded. */
.map-hint { position: absolute; z-index: 5; top: 12px; left: 12px; right: 12px; margin: 0 auto; max-width: 520px;
    padding: .55rem .8rem; border-radius: 8px; font-size: 12px; line-height: 1.4; text-align: center;
    color: #fff; background: rgba(12, 22, 33, .82); border: 1px solid #ffffff2e; box-shadow: 0 6px 18px #0007; }
.map-hint code { background: #ffffff22; padding: .05rem .3rem; border-radius: 4px; }
.btn-action {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .35rem .7rem;
    border-radius: 6px;
    border: 1px solid transparent;
    background: transparent;
    font: inherit;
    font-size: .68rem;
    font-weight: 900;
    letter-spacing: .05em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background-color .15s ease, border-color .15s ease;
}
.btn-action-edit   { color: var(--app-action-edit); background: rgba(68, 166, 213, .12); border-color: rgba(68, 166, 213, .38); }
.btn-action-edit:hover   { background: rgba(68, 166, 213, .22); border-color: rgba(68, 166, 213, .55); }
.btn-action-view   { color: var(--app-action-view); background: rgba(0, 114, 188, .14); border-color: rgba(0, 114, 188, .4); }
.btn-action-view:hover   { background: rgba(0, 114, 188, .26); }
.btn-action-off    { color: var(--app-action-off); background: rgba(247, 144, 9, .14); border-color: rgba(247, 144, 9, .38); }
.btn-action-off:hover    { background: rgba(247, 144, 9, .24); }
.btn-action-delete { color: var(--app-action-delete); background: rgba(237, 28, 36, .1);  border-color: rgba(237, 28, 36, .32); }
.btn-action-delete:hover { background: rgba(237, 28, 36, .2); border-color: rgba(237, 28, 36, .5); }

/* ---- Modal ----------------------------------------------------------------
   Add/edit entries without leaving the register. */
.rms-modal {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: none;
    align-items: flex-start;
    justify-content: center;
    padding: 5vh 16px;
    overflow-y: auto;
    background: var(--app-modal-scrim);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
}
.rms-modal.open { display: flex; }
.rms-modal .modal-box {
    width: min(880px, 100%);
    border-radius: 14px;
    border: 1px solid var(--app-modal-border);
    background: var(--app-modal-bg);
    box-shadow: var(--shadow-lift, 0 24px 70px rgba(11, 31, 63, .28));
    animation: rms-modal-in .22s ease-out both;
}
.rms-modal .modal-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 18px 20px;
    border-bottom: 1px solid var(--app-hairline);
}
.rms-modal .modal-head h2 { font-size: 1rem; }
.rms-modal .modal-head p { font-size: .76rem; opacity: .7; margin-top: 2px; }
.rms-modal .modal-body { padding: 18px 20px; }
.rms-modal .modal-foot {
    display: flex;
    gap: .6rem;
    justify-content: flex-end;
    padding: 14px 20px 18px;
    border-top: 1px solid var(--app-hairline);
}
.modal-close {
    flex: 0 0 auto;
    width: 30px; height: 30px;
    line-height: 1;
    border-radius: 8px;
    border: 1px solid var(--app-ctl-border);
    background: var(--app-ctl-bg);
    color: inherit;
    font-size: 1rem;
    cursor: pointer;
}
.modal-close:hover { background: rgba(237, 28, 36, .2); border-color: rgba(237, 28, 36, .45); }
@keyframes rms-modal-in {
    from { opacity: 0; transform: translateY(-10px) scale(.985); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) { .rms-modal .modal-box { animation: none; } }

/* ---- Sidebar collapse toggle ---------------------------------------------
   Mirrors the prototype's own ≤780px collapsed sidebar (68px, icons only) but
   driven by the user instead of the viewport. */
.sidebar-toggle {
    position: absolute;
    top: 50%;
    right: -13px;
    z-index: 25;
    width: 26px; height: 26px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, .55);
    background: linear-gradient(135deg, #0a84d4, var(--azam-blue, #0072bc));
    color: #fff;
    cursor: pointer;
    box-shadow: 0 3px 10px rgba(0, 0, 0, .45);
    transition: transform .18s ease, filter .15s ease;
}
.sidebar-toggle:hover { filter: brightness(1.12); }
/* On mobile the sidebar is an off-canvas drawer opened by the hamburger, so
   the desktop collapse toggle is hidden (it otherwise peeks at the edge). */
@media (max-width: 780px) { .sidebar-toggle { display: none; } }

/* Client logo in the mobile topbar (created by azam-ui.js). Hidden on desktop
   where the sidebar brand carries it. */
.mobile-topbar-logo { display: none; }
@media (max-width: 780px) {
    .mobile-topbar-logo { display: block; flex: 0 0 auto; height: 30px; width: auto; }
    /* "Azam Media" is hidden on mobile, so the breadcrumb chevron dangles in
       front of the page name — drop it. */
    .topbar .crumb svg { display: none; }
}
.sidebar-toggle svg { width: 14px; height: 14px; margin-left: -1px; }

body.nav-collapsed .sidebar { width: 68px; padding-inline: 8px; }
body.nav-collapsed .main-wrap { width: calc(100% - 68px); margin-left: 68px; }
/* With the rail collapsed, let the content fill the reclaimed width instead of
   staying capped at 1500px and leaving a wide empty margin. */
body.nav-collapsed main { max-width: none; }
/* On mobile the sidebar is an off-canvas drawer, so the desktop "collapsed"
   layout must not apply — otherwise a left-over collapsed state leaves an empty
   68px gap where the off-canvas rail would be. */
@media (max-width: 780px) {
    body.nav-collapsed .main-wrap { width: 100%; margin-left: 0; }
    body.nav-collapsed .sidebar { width: min(82vw, 300px); padding: 18px 14px; }
}
body.nav-collapsed .brand { padding: 0 0 14px; }
body.nav-collapsed .logo-wrap { width: 50px; }
body.nav-collapsed .brand > div:last-child,
body.nav-collapsed .sidebar nav span,
body.nav-collapsed .sidebar nav em,
body.nav-collapsed .nav-arrow,
body.nav-collapsed .nav-section > p,
body.nav-collapsed .sidebar-bottom { display: none; }
body.nav-collapsed .sidebar nav button { justify-content: center; padding: 12px; }
/* Icons get a size bump so a collapsed rail is still readable */
body.nav-collapsed .sidebar nav button svg { width: 22px; height: 22px; }
body.nav-collapsed .sidebar nav button.active::before { left: -8px; }
body.nav-collapsed .sidebar-toggle { transform: rotate(180deg); }

/* Inline reject reason input in the approvals table */
.inline-reason {
    padding: .4rem .6rem; border-radius: 8px; font-family: inherit; font-size: .85rem;
    border: 1px solid var(--app-ctl-border); background: var(--app-ctl-bg); color: inherit;
}
.inline-form { display: inline-flex; gap: .4rem; align-items: center; margin: 0; }
.row-actions { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }

/* ---- Theme toggle ---------------------------------------------------------
   One control in the topbar; the icon shows the theme you would switch TO.
   Both glyphs ship in the markup and CSS picks the right one, so no flash and
   no JS needed to draw the initial state. */
.theme-toggle .theme-icon-dark,
.theme-toggle .theme-icon-light { display: none; }
[data-theme="dark"] .theme-toggle .theme-icon-light { display: block; }
[data-theme="light"] .theme-toggle .theme-icon-dark { display: block; }
.theme-toggle { transition: color .15s ease; }

/* Theme toggle on the signed-out screen.

   Lives inside .login-card rather than in a panel corner: the access panel has
   no corner that stays clear (the card fills it on short viewports, and the
   "All systems operational" chip owns the top-right and moves across five
   breakpoints, with a width that follows its text and so changes under
   Swahili). Anchored to the card, it follows the card at every size. */
.login-card { position: relative; }
.login-theme-toggle {
    z-index: 4;
    position: absolute;
    top: 14px;
    right: 14px;
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    border: 1px solid var(--app-ctl-border);
    background: var(--app-ctl-bg);
    color: inherit;
    cursor: pointer;
    opacity: .75;
    transition: opacity .15s ease, border-color .15s ease;
}
.login-theme-toggle:hover { opacity: 1; border-color: var(--azam-blue, #0072bc); }

/* ---- Login background decor ----------------------------------------------
   Remove the drifting geometric shard "ribbon" (.azam-shard-field) from both
   login panels per request. The SVG network-dot field (.azam-network-field)
   is hidden too because it is replaced by the canvas #particleBg network
   animation (added to the login + app shell layouts). Reversible: delete
   these rules to restore the SVG decor. */
.azam-shard-field   { display: none !important; }
.azam-network-field { display: none !important; }

/* ---- Particle-network background (#particleBg canvas, created by JS) -------
   Fixed full-window layer at z-index:-1 — above the opaque body background but
   behind all in-flow content, so content reads over it without needing a
   stacking context on the shell. (An earlier version put the canvas at z:0 and
   lifted .app-shell to z:1, but that trapped the sidebar below the mobile
   drawer scrim — blurring the drawer and eating taps.) */
#particleBg {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 0;
    pointer-events: none;
}
/* Content sits above the canvas via .main-wrap / .login-page — NOT via
   .app-shell, because giving the shell a stacking context traps the mobile
   drawer below its scrim. The fixed sidebar (z-index:20, drawer 130) already
   stacks above the canvas on its own. Canvas at z:0 paints above the body's
   opaque background, so particles read in both light and dark themes. */
.login-page { position: relative; z-index: 1; }
.main-wrap  { position: relative; z-index: 1; }

/* Let the particle canvas read on the login: drop the page's opaque fill and
   make the access (form) panel translucent so #particleBg drifts behind it.
   The hero/story panel keeps its photo (particles can't show behind an opaque
   image anyway), and the form card stays solid for legibility. */
.login-page   { background: transparent; }
.login-access { background: rgba(249, 250, 252, .82); }
[data-theme="dark"] .login-access {
    background: linear-gradient(155deg, rgba(7, 17, 31, .5), rgba(5, 11, 22, .55) 76%);
}

/* ---- Login: larger primary CTA text --------------------------------------
   The "Sign in securely" button text was only 12px; bump it so the CTA reads
   at a size that matches its weight in the card. */
.login-submit { font-size: 15px; letter-spacing: .2px; }

/* ---- Alert message stacking -----------------------------------------------
   .alert is a flex row of [icon, message]. When a view emits more than one
   message (login validation emits one per field) the extra divs became extra
   flex COLUMNS, so "Enter your password." and "Enter your username or email."
   sat side by side and wrapped mid-phrase. Grid instead: the icon holds
   column 1, every message is pinned to column 2, so they stack. The close
   button azam-ui.js adds sits in the right-hand corner, out of the grid: as a
   grid item it had no column of its own and wrapped onto a line by itself. */
.alert {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
}
.alert::after { grid-column: 1; }
.alert > div { grid-column: 2; }
.alert:has(> .alert-close) { padding-right: 2.6rem; }
.alert > .alert-close { position: absolute; top: 50%; right: .75rem; transform: translateY(-50%); }

/* ---- Login below the side-by-side breakpoint ------------------------------
   The prototype stacks .login-story above .login-access under 1000px and
   gives the story a 430-470px min-height. That is a full screen of hero
   before the sign-in form, so on a phone you land on the image and have to
   scroll to reach the fields.

   Phones: drop the hero and start on the card. Tablets: keep the hero for
   brand presence but cut it to a band so the card is reachable. */
@media (max-width: 1000px) and (min-width: 641px) {
    .login-story,
    .login-story-inner { min-height: 230px; }
    .login-story-inner { padding-top: 28px; padding-bottom: 26px; }
    /* The prototype pins the brand to the top corner and pads the story to clear it; with the
       band cut down, the headline would run over it. In the flow it sits above the headline
       at every tablet width. */
    .login-brand { position: static; transform: none; margin-bottom: 22px; }
    .login-access { padding-top: 26px; }
    /* Pinned to the corner it lands on the card's theme switch once the card fills the width;
       above the card it is still seen and covers nothing. */
    .login-system { position: static; align-self: center; margin-bottom: 14px; }
}

@media (max-width: 640px) {
    .login-story { display: none; }
    .login-access { min-height: 100vh; padding-top: 20px; }
    /* The card carries the wordmark itself once the hero is gone. */
    .login-access .mobile-login-logo { display: block; }
}

/* ---- Ticket detail: key/value pairs + status timeline ---- */
.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px 28px; }
/* Level with the card heading instead of against the card's edge. */
.card > .detail-grid { padding: 0 17px 17px; }
.card > .form-note { margin: 0 17px 17px; }
@media (min-width: 900px) { .detail-cols { display: grid; grid-template-columns: 1.15fr .85fr; gap: 20px; align-items: start; } }
.kv { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.kv > span { font-size: 11px; letter-spacing: .04em; text-transform: uppercase; opacity: .6; }
.kv > strong { font-weight: 600; word-break: break-word; }
.kv.span-2 { grid-column: 1 / -1; }

.timeline { list-style: none; margin: 4px 0 0; padding: 0; position: relative; }
.timeline::before { content: ""; position: absolute; left: 7px; top: 6px; bottom: 6px; width: 2px; background: var(--app-hairline); }
.timeline > li { position: relative; padding: 0 0 18px 30px; }
.timeline > li:last-child { padding-bottom: 2px; }
.timeline > li::before { content: ""; position: absolute; left: 2px; top: 3px; width: 12px; height: 12px; border-radius: 50%; background: var(--azam-blue, #0072bc); box-shadow: 0 0 0 3px var(--app-ctl-bg); }
.timeline > li.done::before { background: var(--app-hairline); }
.timeline .tl-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }
.timeline .tl-when { margin-left: auto; font-size: 12px; opacity: .6; white-space: nowrap; }
.timeline .tl-from { font-size: 12px; opacity: .6; }
.timeline .tl-reason { font-size: 13px; opacity: .75; margin-top: 2px; }
/* Where the step was done: distance from the centre, or why no location was given. */
.timeline .tl-where { font-size: 12px; color: var(--gray-500); margin-top: 2px; }

.card-gap-top { margin-top: 20px; }

/* Audit trail */
.audit-filters { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; align-items: end; }
.audit-filter-actions { display: flex; gap: 8px; align-items: center; }
.mono { font-variant-numeric: tabular-nums; letter-spacing: .01em; font-size: 12px; }
.dim { color: var(--app-subtext-fg); opacity: 1; }
.audit-detail > summary { cursor: pointer; color: var(--azam-blue, #0072bc); font-weight: 600; user-select: none; }
.audit-detail[open] > summary { margin-bottom: 6px; }
.audit-json { margin: 4px 0; }
.audit-json-label { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .05em; opacity: .55; margin-bottom: 2px; }
.audit-json pre { margin: 0; padding: 8px 10px; background: var(--app-ctl-bg, rgba(0,0,0,.03)); border: 1px solid var(--app-hairline); border-radius: 8px; font-variant-numeric: tabular-nums; letter-spacing: .01em; font-size: 11.5px; white-space: pre-wrap; word-break: break-word; }

/* Object-storage connection test */
.storage-test { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 14px; }
.storage-test small { opacity: .7; }

/* Dropdowns inside a .input wrapper.
   .input select sets appearance:none to inherit the wrapper's styling, which also removes the
   native caret and leaves a dropdown looking exactly like a text box. Draw the caret back on the
   wrapper (currentColor, so it works in both themes) and make the option popup follow the theme. */
.input:has(select) { cursor: pointer; }
/* Some wrappers (the master-data modals) already ship their own <svg> chevron in the markup.
   Drawing the CSS caret as well gave those dropdowns two arrows, so only draw it where the
   markup supplies none. */
.input:has(select):has(svg)::after { content: none; }
.input:has(select) > svg { flex: 0 0 auto; margin-left: 8px; opacity: .55; pointer-events: none; }
.input:has(select)::after {
    content: "";
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    margin-left: 8px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
    opacity: .55;
    pointer-events: none;
}
/* The wrapper draws its own caret above, so the select must drop the native one - without
   appearance:none both were painted and every dropdown showed a double chevron. Strip the
   select back to bare text and let the .input wrapper supply the box. */
.input select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    /* .input is a flex row that also holds the caret, so the select has to share the row.
       width:100% fought the caret for space and pushed the value off centre; let it flex
       instead and allow it to shrink below its content width. */
    flex: 1 1 auto;
    min-width: 0;
    align-self: stretch;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    line-height: normal;
    text-indent: 0;
    cursor: pointer;
}
.input select:focus { outline: none; }
/* The option popup is painted by the OS and does not inherit the page, so colour it per theme
   or it opens as a white list on the dark panel. */
.input select option,
.rms-modal select option {
    background: var(--white, #fff);
    color: var(--gray-900, #1a2333);
}
[data-theme="dark"] .input select option,
[data-theme="dark"] .rms-modal select option {
    background: #16233c;
    color: #eef6ff;
}

/* Chrome paints autofilled fields with its own background, which overrides the theme and makes a
   remembered username sit in a differently-coloured block (login screen, settings, masters).
   The modal rule above only covered .rms-modal, so cover the standard .input wrapper too.
   An autofilled input cannot be made transparent, so fill it with the surrounding colour. */
.input input:-webkit-autofill,
.input input:-webkit-autofill:hover,
.input input:-webkit-autofill:focus,
.input input:-webkit-autofill:active {
    -webkit-text-fill-color: var(--gray-900, #1a2333);
    -webkit-box-shadow: 0 0 0 1000px var(--white, #fff) inset;
    caret-color: var(--gray-900, #1a2333);
    transition: background-color 5000s ease-in-out 0s;   /* stop Chrome re-tinting on focus */
}
:root[data-theme="dark"] .input input:-webkit-autofill,
:root[data-theme="dark"] .input input:-webkit-autofill:hover,
:root[data-theme="dark"] .input input:-webkit-autofill:focus,
:root[data-theme="dark"] .input input:-webkit-autofill:active {
    -webkit-text-fill-color: #eef6ff;
    -webkit-box-shadow: 0 0 0 1000px #16233c inset;
    caret-color: #eef6ff;
}

/* Object-storage test row. It previously sat flush against the fields above and the secrets note
   below, so the three ran together as one strip. Separate it with a rule and real spacing, and
   give the action a filled treatment so it reads as a button rather than a link (blue, so it does
   not compete with the red primary Save). */
.storage-test {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin: 18px 0 0;
    padding-top: 16px;
    border-top: 1px solid var(--app-hairline);
}
.storage-test .button {
    background: var(--azam-blue, #0072bc);
    border: 1px solid var(--azam-blue, #0072bc);
    color: #fff;
}
.storage-test .button:hover { background: var(--azam-blue-dark, #273691); border-color: var(--azam-blue-dark, #273691); }
.storage-test small { opacity: .72; }

/* Keep the encrypted-secrets note clear of whatever sits above it. */
.tab-panel .form-note { margin-top: 16px; }

/* Settings panels: the fields sat tight against each other and their help text, so rows ran
   together. Give the grid real row spacing, tie each hint to its own field, and keep the panel
   heading and the closing note clear of the grid. Scoped to the settings tabs so the prototype's
   .form-grid is untouched everywhere else. */
.tab-panel .form-grid { gap: 22px 22px; align-items: start; }
.tab-panel .form-grid .field { gap: 6px; }
.tab-panel .field-help { display: block; margin-top: 2px; line-height: 1.4; opacity: .72; }
.tab-panel .card-head { margin-bottom: 18px; }
.tab-panel { padding-bottom: 4px; }

/* Settings panels were reading as a stack of full-width bands — heading, fields, action row and
   two notes each separated by a rule across the whole card. Soften them into contained blocks so
   the eye groups the fields rather than the dividers. */
.tab-panel .card-head { margin-bottom: 16px; padding-bottom: 12px; }
.tab-panel .form-note,
.tab-panel .storage-test {
    border: 1px solid var(--app-hairline);
    border-radius: 10px;
    background: var(--app-ctl-bg);
    padding: 12px 14px;
}
.tab-panel .form-note {
    margin-top: 14px;
    font-size: 12px;
    line-height: 1.5;
    align-items: flex-start;
    gap: 10px;
}
.tab-panel .form-note svg { flex: 0 0 auto; margin-top: 2px; opacity: .8; }
.tab-panel .storage-test { margin-top: 18px; border-top: 1px solid var(--app-hairline); }
/* The test row is an action, not another form row — keep it compact and left-aligned. */
.tab-panel .storage-test .field { flex: 0 1 300px; }
.tab-panel .storage-test small { flex: 1 1 220px; font-size: 12px; }

/* Closer to the reference: each settings section should read as one contained card with room to
   breathe, not a stack of full-width bands cut by rules. Drop the dividers, pad the card, and let
   the inset blocks (note, test row) carry the structure instead. */
.tab-panel { padding: 22px 24px 20px; }
.tab-panel .card-head {
    border-bottom: 0;
    padding-bottom: 0;
    margin-bottom: 20px;
}
.tab-panel .card-head h2 { margin-bottom: 2px; }
.tab-panel .card-head p { opacity: .7; }
.tab-panel .storage-test { border-top: 0; }
.tab-panel > .form-note:last-child { margin-bottom: 2px; }
/* Buttons in these blocks size to their content rather than stretching the row. */
.tab-panel .storage-test .button { flex: 0 0 auto; }

/* Match the reference layout: a readable, constrained column of stacked fields rather than a
   three-across grid stretched over the full page width — that width is most of why the settings
   read as cluttered. Two columns only where there is genuinely room. */
#settings-form .tabs { max-width: 1440px; }
.tab-panel .form-grid { grid-template-columns: 1fr; gap: 18px; }
@media (min-width: 1100px) {
    .tab-panel .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 20px; }
    /* Long values (endpoints, mailboxes) get the full width rather than wrapping awkwardly. */
    .tab-panel .form-grid .field-wide { grid-column: 1 / -1; }
}
.tab-panel .form-grid .field > span { font-size: 11px; letter-spacing: .04em; }

/* Test actions sit beside the red primary Save, so give them the same shape and weight but the
   Outlined blue, the same secondary treatment as Bulk import and Edit: red stays reserved for
   the primary action. Shape, radius and padding come from .button so the two read as siblings. */
.tab-panel .storage-test .button {
    color: var(--app-action-edit);
    background: rgba(68, 166, 213, .12);
    border: 1px solid rgba(68, 166, 213, .38);
    box-shadow: none;
}
.tab-panel .storage-test .button:hover {
    background: rgba(68, 166, 213, .22);
    border-color: rgba(68, 166, 213, .55);
}

/* Show/hide control on secret inputs. Sits inside the field wrapper so it reads as part of it. */
.input .reveal {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    padding: 0 2px;
    border: 0;
    background: transparent;
    color: inherit;
    opacity: .5;
    cursor: pointer;
}
.input .reveal:hover { opacity: .85; }
.input .reveal.is-on { opacity: 1; color: var(--azam-blue, #0072bc); }

/* A switch is not a text field: drop the input border/background around it so it reads as a
   control in its own right rather than a value sitting in a box. */
.input:has(.setting-toggle) {
    border: 0;
    background: transparent;
    padding: 0;
    min-height: 0;
}
.input:has(.setting-toggle) .setting-toggle { gap: 10px; }

/* Centre the settings column. Everything on the page shares one axis so the heading, banner,
   tabs and the secrets card line up instead of the content hugging the left edge of a wide screen.
   Scoped by the settings form so no other page is affected. */
body:has(#settings-form) .page-header,
body:has(#settings-form) .alert,
body:has(#settings-form) .card-gap-top,
#settings-form .tabs {
    max-width: 1440px;
    margin-inline: auto;
}

/* Long values (an endpoint URL) need the full row - at half width the address is cut off. */
.tab-panel .form-grid .field:has(input[name="Storage.ServiceUrl"]),
.tab-panel .form-grid .field:has(input[name="Sms.BaseUrl"]) { grid-column: 1 / -1; }

/* The note is a flex row, so bare text and a <b> became separate flex items and wrapped into
   columns. Keep the icon as the only sibling and let the text flow as one block. */
.tab-panel .form-note > span { flex: 1 1 auto; }

/* Account menu. The avatar chip in the top bar already showed a chevron but had no menu behind it;
   Help centre and Sign out now live here instead of at the foot of the sidebar, which is where a
   user looks for them. */
.user-menu { position: relative; }
.user-menu > .user { cursor: pointer; user-select: none; }
.user-menu > .user svg { transition: transform .15s ease; }
.user-menu.open > .user svg { transform: rotate(180deg); }
.user-menu .menu {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 70;
    display: none;
    min-width: 208px;
    padding: 6px;
    border-radius: 12px;
    border: 1px solid var(--app-modal-border);
    background: var(--app-modal-bg);
    box-shadow: var(--app-shadow-lift, 0 18px 46px rgba(11, 31, 63, .32));
}
.user-menu.open .menu { display: block; }
.user-menu .menu form { margin: 0; }
/* Links sit in the menu alongside buttons (Sign out is a form), so they share one look. */
.user-menu .menu button,
.user-menu .menu a {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 11px;
    border: 0;
    border-radius: 8px;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    text-decoration: none;
}
.user-menu .menu button:hover,
.user-menu .menu a:hover { background: var(--app-row-hover); }
.user-menu .menu button.soon { color: var(--app-help-fg); cursor: default; }
.user-menu .menu .sep { height: 1px; margin: 5px 6px; background: var(--app-hairline); }

/* ---- Row actions: one palette across every register --------------------------
   Repair centres tagged each action with its own btn-action-* class; every other master
   emits a plain "button secondary", so Edit / Deactivate / Delete all rendered identically.
   Rather than re-tagging nine views, colour them by what the button actually does - the
   posting form's action is a dependable hook, and Edit is the button that posts nowhere.
   Result: the same meaning carries the same colour on every page.
      Edit  blue outline · Proof/view  solid blue · Deactivate  amber · Delete  red        */
.row-actions .button.secondary,
.row-actions form[action*="Active"] > .button,
.row-actions form[action*="Delete"] > .button {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .35rem .7rem;
    border-radius: 6px;
    border: 1px solid transparent;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
/* Edit - the one action that is not a form post. */
.row-actions > .button.secondary {
    color: var(--app-action-edit);
    background: rgba(68, 166, 213, .12);
    border-color: rgba(68, 166, 213, .38);
}
.row-actions > .button.secondary:hover {
    background: rgba(68, 166, 213, .22);
    border-color: rgba(68, 166, 213, .55);
}
/* Activate / Deactivate. */
.row-actions form[action*="Active"] .button {
    color: var(--app-action-off);
    background: rgba(247, 144, 9, .14);
    border-color: rgba(247, 144, 9, .38);
}
.row-actions form[action*="Active"] .button:hover { background: rgba(247, 144, 9, .24); }
/* Delete stays the only red control in the row. */
.row-actions form[action*="Delete"] .button {
    color: var(--app-action-delete);
    background: rgba(237, 28, 36, .1);
    border-color: rgba(237, 28, 36, .32);
}
.row-actions form[action*="Delete"] .button:hover {
    background: rgba(237, 28, 36, .2);
    border-color: rgba(237, 28, 36, .5);
}
/* Keep the row on one line - stacked buttons were making rows three times taller. */
.row-actions { display: flex; flex-wrap: nowrap; align-items: center; gap: 8px; }
.row-actions form { margin: 0; }

/* The card header now carries the search box alongside the title and buttons. */
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.card-head-actions { flex-wrap: wrap; justify-content: flex-end; }
.card-head-actions .grid-search { min-width: 200px; }

/* Empty states ("No customers yet.", "No audit events match these filters.") were a bare
   line of text jammed under the header. Give them the room a table would have occupied so
   the card does not collapse to a sliver. */
.card > p:last-child {
    margin: 0;
    padding: 34px 16px 38px;
    border-top: 1px solid var(--app-hairline);
    color: var(--app-help-fg);
    text-align: center;
}

/* At the wider column the two-across grid leaves each field roomy enough that the
   long values no longer need their own row. */
@media (min-width: 1500px) {
    .tab-panel .form-grid { gap: 18px 28px; }
}

/* Card header order: title left, search centred in the gap, action buttons right. */
.card-head > .grid-search { margin-inline: auto; min-width: 240px; }
.card-head > .card-head-actions { margin-left: 0; }

/* Card headings had no explicit size, so nested <section> shrank them to body size and the
   section titles read as ordinary text. Give them one deliberate scale across every card. */
.card-head h2 {
    margin: 0 0 3px;
    font-size: 17px;
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: -.005em;
}
.card-head p { margin: 0; font-size: 12.5px; color: var(--app-help-fg); }

/* True centring for the search box: title and action group share the leftover space evenly,
   so the box sits mid-header rather than drifting toward the buttons. */
.card-head > :first-child { flex: 1 1 0; min-width: 0; }
.card-head > .card-head-actions { flex: 1 1 0; justify-content: flex-end; }
.card-head > .grid-search { flex: 0 0 auto; margin-inline: 0; }

/* .header-actions is the other wrapper used for card-header buttons; it gets the same
   right-hand placement as .card-head-actions. */
.card-head > .header-actions { display: flex; align-items: center; gap: .6rem; flex: 1 1 0; justify-content: flex-end; }

/* Flex with equal bases still let a long title or a wide button pull the search off centre.
   A three-track grid pins the arrangement: the title takes the left track and the free space,
   so the search and the action buttons stay together as one cluster on the right. */
.card-head:has(> .grid-search) {
    display: grid;
    grid-template-columns: 1fr auto auto;
    align-items: center;
    column-gap: 12px;
    padding-block: 4px 14px;
}
.card-head:has(> .grid-search) > :first-child { grid-column: 1; }
.card-head:has(> .grid-search) > .grid-search { grid-column: 2; min-width: 260px; margin: 0; }
.card-head:has(> .grid-search) > .card-head-actions,
.card-head:has(> .grid-search) > .header-actions { grid-column: 3; justify-self: end; }

/* Headers that carry no search keep the simple two-end layout. */
.card-head:not(:has(> .grid-search)) { padding-block: 4px 14px; }

/* The actions cell shares the leftover table width, so its buttons floated in the middle of
   a wide empty column. Pin them to the right edge, matching the register layout. */
td:has(> .row-actions) { text-align: right; }
td:has(> .row-actions) > .row-actions { justify-content: flex-end; }

/* The test row centres its items against the whole field block - and that block is taller than
   the input because it carries a label above it, so the button and the hint floated above the
   box they belong to. Align on the bottom edge instead and give the button and hint the input's
   own height, so all three line up with the text box rather than with its label. */
.storage-test { align-items: flex-end; }
.storage-test .field { margin: 0; }
.storage-test .button,
.storage-test > .input,
.storage-test input { min-height: 40px; }
.storage-test small { align-self: flex-end; min-height: 40px; display: flex; align-items: center; }

/* Field hints were dimmed with opacity on top of an already-soft colour, which left them
   barely legible on the dark panel. Use the help colour the theme defines - it is tuned for
   contrast in both themes - and drop the opacity. */
.field-help,
.tab-panel .field-help {
    color: var(--app-help-fg);
    opacity: 1;
    font-size: 11.5px;
}
.storage-test small { color: var(--app-help-fg); opacity: 1; }

/* .field sets display:flex, which outranks the browser's [hidden] { display: none }, so a
   field hidden from script stayed on screen. Make hiding win wherever it is applied. */
[hidden] { display: none !important; }

/* Native popups - the select's option list, date pickers, scrollbars - are painted by the
   browser, not the page, and follow color-scheme rather than any colour we set. Without this
   the dark theme opened a white option list; the per-option colours alone were not enough
   (Chrome derives the popup from the select's own background, which we clear to sit inside
   the .input wrapper). */
:root { color-scheme: light; }
:root[data-theme="dark"], [data-theme="dark"] { color-scheme: dark; }
[data-theme="dark"] .input select,
[data-theme="dark"] .rms-modal select { background-color: transparent; }

/* KPI cards: the label and the sub-note were 10/10.5px and hard to read next to a 21px figure.
   Raise all three a step and tighten the line heights and margin by the same amount, so the
   card keeps its 105px height rather than growing. */
.stats-grid .stat span { font-size: 11.5px; line-height: 1.25; }
.stats-grid .stat strong { font-size: 25px; line-height: 1.1; margin: 1px 0; }
.stats-grid .stat small { font-size: 12px; line-height: 1.2; }

/* ---- Bare <select> in a modal ------------------------------------------------
   Two dropdown patterns exist. Most modals wrap the control as
   .field > .input > select, which gets the caret drawn on the wrapper. Some -
   the user dialogs among them - put the select straight in the field with no
   wrapper, so none of those rules reached it: it kept the native caret, the
   native height and its own padding, and sat visibly differently from every
   other dropdown. Give it the same treatment. There is no wrapper to hang a
   caret on, so it is painted as a background image instead. */
.rms-modal .field > select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    min-height: 40px;
    padding-right: 34px;
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 12px 12px;
    /* Chevron, matching the inline SVG the wrapped dropdowns use. */
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%233d4757' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    cursor: pointer;
}
:root[data-theme="dark"] .rms-modal .field > select {
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a9d6f2' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}

/* ---- Styled dropdown ---------------------------------------------------------
   Replaces the operating system's option list, which sits outside the page and
   cannot be aligned to the field or themed. The native <select> is still there,
   still posts the form and still holds the value; it is only hidden from view. */
.rms-select { position: relative; display: block; width: 100%; }

/* Kept in the DOM for the form post, taken out of the layout and off the tab order. */
select.rms-select-native {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    border: 0;
}

.rms-select-trigger {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: 40px;
    padding: 0 11px;
    border-radius: 8px;
    border: 1px solid var(--app-ctl-border);
    background: var(--app-ctl-bg);
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: border-color .15s, box-shadow .15s;
}
.rms-select-trigger:hover { border-color: var(--sky-500, #44a6d5); }
.rms-select-trigger:focus-visible,
.rms-select.open .rms-select-trigger {
    outline: none;
    border-color: var(--azam-blue, #0072bc);
    box-shadow: 0 0 0 3px #0072bc22;
}
.rms-select-value { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rms-select-value.placeholder { color: var(--app-help-fg); }
.rms-select-caret { flex: 0 0 auto; width: 15px; height: 15px; opacity: .6; transition: transform .15s ease; }
.rms-select.open .rms-select-caret { transform: rotate(180deg); }

/* Inside a .input wrapper the wrapper already draws the box, so the trigger must not
   draw a second one. */
.input > .rms-select .rms-select-trigger {
    border: 0;
    background: none;
    min-height: 0;
    padding: 0;
    box-shadow: none;
}
.input:has(.rms-select)::after { content: none; }   /* the trigger carries its own caret */
.input:has(.rms-select) > svg { display: none; }    /* and so does the markup's chevron */

.rms-select-menu {
    position: absolute;
    z-index: 80;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    display: none;
    max-height: 260px;
    overflow-y: auto;
    padding: 5px;
    border-radius: 10px;
    border: 1px solid var(--app-modal-border);
    background: var(--app-modal-bg);
    box-shadow: var(--app-shadow-lift, 0 12px 32px rgba(11, 31, 63, .28));
}
.rms-select.open .rms-select-menu { display: block; }
.rms-select.drop-up .rms-select-menu { top: auto; bottom: calc(100% + 6px); }

.rms-select-option {
    padding: 8px 10px;
    border-radius: 6px;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* A clear full-row highlight, so the keyboard position and the mouse position read the
   same way. */
.rms-select-option.active { background: rgba(68, 166, 213, .20); }
:root[data-theme="dark"] .rms-select-option.active { background: rgba(88, 178, 230, .26); }
.rms-select-option.selected { color: var(--app-action-view); font-weight: 700; }

/* A dropdown inside a modal has to sit above the dialog's own stacking context. */
.rms-modal .rms-select-menu { z-index: 90; }

/* Audit detail: field and value rows rather than raw JSON. The details column is the last of
   eight, so it is narrow - stack each label above its value rather than let a two-column grid
   squeeze values into breaking mid-word. */
.audit-values { margin: 6px 0 0; }
.audit-values dt { margin-top: 7px; color: var(--app-help-fg); font-size: 11px; letter-spacing: .03em; text-transform: uppercase; }
.audit-values dt:first-child { margin-top: 0; }
.audit-values dd { margin: 1px 0 0; overflow-wrap: anywhere; }
/* Give the opened panel room to breathe without widening the closed column. */
.audit-detail[open] { display: block; min-width: 240px; }
.audit-detail[open] .audit-json + .audit-json { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--app-hairline); }

/* The second line in a cell - a device model under its serial, a phone under a customer name -
   inherited the prototype's mid-grey, which is close to unreadable on the dark rows. Give it a
   tone that holds its own against the row without competing with the value above it. */
td small,
.grid-wrap td small {
    color: var(--app-subtext-fg);
    font-size: 11.5px;
    line-height: 1.35;
    opacity: 1;
}

/* The prototype clips cards (overflow:hidden) to keep rounded corners tidy, which also cuts off
   a dropdown opened near the bottom of one. Let the card show overflow only while a dropdown is
   open, so nothing else about it changes. */
.card:has(.rms-select.open),
.tab-panel:has(.rms-select.open),
.modal-box:has(.rms-select.open),
.grid-wrap:has(.rms-select.open) { overflow: visible; }

/* Above the cards and the sticky table header it may open across. */
.rms-select.open { position: relative; z-index: 120; }
.rms-select-menu { z-index: 120; }
.rms-modal .rms-select-menu { z-index: 130; }

/* A typed-in account of a fault needs room to breathe inside the .input box. */
.input:has(textarea) { align-items: stretch; padding-top: 8px; padding-bottom: 8px; }
.input textarea {
    width: 100%;
    min-width: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    line-height: 1.45;
    resize: vertical;
}
.input textarea:focus { outline: none; }

/* Evidence upload row on the diagnosis screen. */
.evidence-add { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; margin: 4px 0 14px; }
.evidence-add .button { flex: 0 0 auto; min-height: 40px; }
.evidence-add small { color: var(--app-help-fg); min-height: 40px; display: flex; align-items: center; }
.input input[type="file"] { border: 0; background: none; color: inherit; font: inherit; width: 100%; }

/* Business rules: each rule shown as the rule itself - what it says, what it does, and whether
   Azam is applying it - as a card, grouped by the part of the job it governs. Sized to be read,
   not scanned: these sentences are the policy. */
.rule-groups { display: grid; gap: 1.4rem; }
.rule-group-head { margin-bottom: .7rem; }
.rule-group-head h3 { font-size: 15px; font-weight: 800; color: var(--navy-900); }
.rule-group-head p { font-size: 13px; color: var(--gray-500); margin-top: .15rem; }
/* Three to a row: wide enough for a rule sentence to read in two or three lines. */
.rule-list { display: grid; gap: 1rem; grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 1180px) { .rule-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 720px) { .rule-list { grid-template-columns: 1fr; } }
.rule { border: 1px solid var(--gray-200); border-radius: var(--radius, 12px); padding: 1rem 1.1rem;
    background: var(--white); display: flex; flex-direction: column; gap: .7rem;
    box-shadow: 0 1px 2px #0b1f3f0f; }
.rule-head { display: flex; align-items: flex-start; justify-content: space-between; gap: .9rem; }
.rule-head h4 { font-size: 15px; line-height: 1.35; font-weight: 800; color: var(--navy-900); margin: 0; }
.rule-statement { font-size: 14px; line-height: 1.55; color: var(--gray-700); margin: 0; flex: 1; }
.rule-switch { flex: none; }
.rule-switch .setting-state { font-size: 12.5px; font-weight: 700; white-space: nowrap; }
.rule-foot { display: flex; align-items: center; justify-content: space-between; gap: .8rem; flex-wrap: wrap;
    padding-top: .7rem; border-top: 1px solid var(--gray-200); }
/* What the rule does when it bites: the second thing an administrator needs, so it is a readable
   label rather than a 10px badge. */
.rule-effect { display: inline-flex; align-items: center; gap: .45rem; font-size: 12.5px; font-weight: 700;
    color: var(--green-600); background: var(--green-100); border-radius: 999px; padding: 5px 12px; }
.rule-effect::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.rule-effect.is-off { color: var(--gray-500); background: var(--gray-100); }
.rule-number { display: inline-flex; align-items: center; gap: .55rem; color: var(--gray-500); font-size: 13px; font-weight: 600; }
.rule-number input { width: 5.5rem; padding: .45rem .6rem; font-size: 14px; border: 1px solid var(--gray-300);
    border-radius: 8px; background: var(--white); color: var(--gray-900); }
.rule-reason { display: grid; gap: .35rem; }
.rule-reason span { color: var(--gray-500); font-size: 13px; font-weight: 600; }
.rule-reason input { padding: .5rem .65rem; font-size: 14px; border: 1px solid var(--gray-300); border-radius: 8px;
    background: var(--white); color: var(--gray-900); }
/* A rule that is not being applied stays readable - it is still a rule Azam owns, just stood down. */
.rule-off { border-style: dashed; box-shadow: none; }
.rule-off .rule-statement { color: var(--gray-500); }

:root[data-theme="dark"] .rule-group-head h3 { color: #e8eef7; }
:root[data-theme="dark"] .rule-group-head p { color: #9db0c9; }
:root[data-theme="dark"] .rule { background: #14243c; border-color: #2a4668; box-shadow: none; }
:root[data-theme="dark"] .rule-head h4 { color: #f2f6fb; }
:root[data-theme="dark"] .rule-statement { color: #c9d6e8; }
:root[data-theme="dark"] .rule-foot { border-top-color: #26405f; }
:root[data-theme="dark"] .rule-effect { color: #5fd3a0; background: #123a2e; }
:root[data-theme="dark"] .rule-effect.is-off { color: #9db0c9; background: #1b2e48; }
:root[data-theme="dark"] .rule-off .rule-statement { color: #8ea2bd; }
:root[data-theme="dark"] .rule-number input,
:root[data-theme="dark"] .rule-reason input { background: #0f1c30; border-color: #2c4869; color: #e8eef7; }
:root[data-theme="dark"] .rule-number,
:root[data-theme="dark"] .rule-reason span { color: #9db0c9; }
:root[data-theme="dark"] .rule-off { border-color: #3a5c85; }

/* Device receipt - the customer's proof that Azam holds their box. Printable: the print rules
   drop the shell and leave the receipt alone on the page. */
.receipt { max-width: 780px; }
.receipt-head { display: flex; justify-content: space-between; align-items: flex-start;
    gap: 1rem; padding-bottom: .8rem; border-bottom: 2px solid var(--azam-blue); }
.receipt-head h2 { font-size: 1.05rem; font-weight: 900; color: var(--navy-900); }
.receipt-head p { color: var(--gray-500); margin-top: .2rem; }
.receipt-number { text-align: right; }
.receipt-number span { display: block; color: var(--gray-500); font-size: .75rem;
    text-transform: uppercase; letter-spacing: .05em; }
.receipt-number b { font-size: 1.05rem; color: var(--azam-red); }
.receipt-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: .7rem 1.4rem; margin: 1rem 0 0; }
.receipt-grid dt { color: var(--gray-500); font-size: .75rem; text-transform: uppercase;
    letter-spacing: .05em; }
.receipt-grid dd { margin: .15rem 0 0; font-weight: 700; color: var(--navy-900); }
.receipt-note { margin-top: .9rem; color: var(--gray-700); }
.receipt-items { margin-top: 1.1rem; }
.receipt-items h3 { font-size: .8rem; text-transform: uppercase; letter-spacing: .05em;
    color: var(--gray-500); }
.receipt-items ul { margin: .4rem 0 0; padding-left: 1.1rem; color: var(--gray-900); }
.receipt-items li { margin: .2rem 0; }
.receipt-ack { margin-top: 1.2rem; padding-top: .8rem; border-top: 1px dashed var(--gray-300);
    color: var(--gray-700); }
.receipt-sign { display: flex; gap: 2.5rem; margin-top: 2.2rem; }
.sign-line { flex: 1; border-top: 1px solid var(--gray-300); padding-top: .35rem; }
.sign-line span { color: var(--gray-500); font-size: .78rem; }

:root[data-theme="dark"] .receipt-head h2,
:root[data-theme="dark"] .receipt-grid dd { color: #e8eef7; }
:root[data-theme="dark"] .receipt-note,
:root[data-theme="dark"] .receipt-ack,
:root[data-theme="dark"] .receipt-items ul { color: #b7c6da; }

@media print {
    .no-print, .sidebar, .topbar, .app-nav, .breadcrumbs { display: none !important; }
    body { background: #fff; }
    .app-shell, .app-main, .content { margin: 0 !important; padding: 0 !important; display: block !important; }
    .receipt { box-shadow: none; border: 0; max-width: none; color: #000; }
    .receipt-grid dd, .receipt-head h2 { color: #000; }
}

/* Replacement boxes: two lanes, the new box travelling to the centre and the old one back to Azam. */
.box-lanes { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: .9rem; margin-top: 12px; }
.box-lane { border: 1px solid var(--gray-200); border-radius: var(--radius, 12px); padding: .8rem .9rem;
    display: grid; gap: .6rem; align-content: start; }
.box-lane-head { display: flex; justify-content: space-between; align-items: flex-start; gap: .8rem; }
.box-lane-head h3 { font-size: .92rem; font-weight: 800; color: var(--navy-900); }
.box-lane-head p { color: var(--gray-500); font-size: .8rem; margin-top: .1rem; }
.box-steps { list-style: none; margin: 0; padding: 0 0 0 .9rem; border-left: 2px solid var(--gray-200); display: grid; gap: .55rem; }
.box-steps li { position: relative; display: grid; gap: .1rem; }
.box-steps li::before { content: ""; position: absolute; left: calc(-.9rem - 6px); top: .35rem; width: 10px; height: 10px;
    border-radius: 50%; background: var(--azam-blue); box-shadow: 0 0 0 3px var(--white); }
.box-steps b { color: var(--gray-900); font-weight: 700; }
.box-steps span { color: var(--gray-500); font-size: .8rem; }
.box-steps em { color: var(--gray-700); font-size: .82rem; font-style: normal; }
.box-step-form { display: grid; gap: .5rem; }
.box-step-form .input input { width: 100%; }
.box-step-buttons { display: flex; flex-wrap: wrap; gap: .5rem; }

:root[data-theme="dark"] .box-lane { border-color: #26405f; }
:root[data-theme="dark"] .box-lane-head h3,
:root[data-theme="dark"] .box-steps b { color: #e8eef7; }
:root[data-theme="dark"] .box-steps { border-color: #26405f; }
:root[data-theme="dark"] .box-steps em { color: #b7c6da; }
:root[data-theme="dark"] .box-steps li::before { box-shadow: 0 0 0 3px #14243c; }

/* Save bar at the foot of a long settings form: it sticks to the bottom of the screen while the
   form scrolls, and settles in place once the end of the form is reached. */
.save-bar { position: sticky; bottom: 12px; z-index: 5; display: flex; align-items: center;
    justify-content: flex-end; gap: 1rem; margin-top: 16px; padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, .08); border-radius: 12px;
    background: rgba(13, 29, 51, .82); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
    box-shadow: 0 8px 24px rgba(0, 0, 0, .28); }
.save-bar span { color: #9db0c9; font-size: 13px; }
[data-theme="light"] .save-bar { background: rgba(255, 255, 255, .88); border-color: rgba(11, 31, 63, .08);
    box-shadow: 0 8px 24px rgba(11, 31, 63, .10); }
[data-theme="light"] .save-bar span { color: var(--gray-500); }

/* An error shown inside a dialog, above the fields it is about. */
.modal-alert { margin: 0 0 14px; }
/* The field a refused save was about, so the eye goes straight to it. */
.field.field-error .input { border-color: var(--red-600, #d92d20) !important;
    box-shadow: 0 0 0 3px rgba(217, 45, 32, .18); }
.field.field-error > span { color: var(--red-600, #d92d20); }

/* A system-issued code (CUS-100005): fixed-width so a column of them lines up. */
.code-chip { font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace; font-size: 12.5px;
    font-weight: 700; letter-spacing: .02em; color: var(--azam-blue, #0072bc); }
:root[data-theme="dark"] .code-chip { color: #7cc4f0; }
input[readonly] { cursor: default; opacity: .85; }

/* A count badge that opens something (the proof documents), so it looks clickable. */
.badge-button { border: 0; cursor: pointer; font: inherit; font-size: 11px; font-weight: 800; }
.badge-button:hover { filter: brightness(1.15); text-decoration: underline; }
/* A wider dialog for a table of documents. */
.modal-box.modal-wide { width: min(880px, 94vw); max-width: 94vw; }
.doc-table td .button { padding: 4px 12px; }

/* Agent / technician picker on the centre form: the new-person fields open beneath it. */
.staff-new { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 12px;
    margin-top: 10px; padding: 12px; border: 1px dashed var(--gray-300); border-radius: 10px; }
.staff-new .field-help { grid-column: 1 / -1; }
:root[data-theme="dark"] .staff-new { border-color: #2c4869; }
/* A centre's technicians, each a chip with a button to take them off. */
.tech-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 8px; }
.tech-chips:empty { display: none; }
.tech-chip { display: inline-flex; align-items: center; gap: 6px; }
.tech-chip-remove { border: 0; background: transparent; color: inherit; cursor: pointer; font-size: 1rem; line-height: 1; padding: 0 2px; opacity: .7; }
.tech-chip-remove:hover { opacity: 1; }
@media (max-width: 720px) { .staff-new { grid-template-columns: 1fr; } }

/* Search-as-you-type list under an intake input. */
.input.typeahead { position: relative; }
.typeahead-menu { position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 30;
    max-height: 300px; overflow-y: auto; padding: 4px; border-radius: 10px;
    background: var(--white); border: 1px solid var(--gray-200); box-shadow: 0 12px 28px rgba(11, 31, 63, .18); }
.typeahead-item { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; width: 100%; text-align: left;
    padding: 8px 10px; border: 0; border-radius: 8px; background: none; color: inherit; font: inherit; cursor: pointer; }
.typeahead-item b { font-weight: 800; color: var(--navy-900); }
.typeahead-item span { grid-column: 1; color: var(--gray-500); font-size: 12.5px; }
.typeahead-item em { grid-column: 2; grid-row: 1 / span 2; align-self: center; font-style: normal;
    font-size: 11.5px; font-weight: 700; color: var(--azam-blue); }
.typeahead-item.active, .typeahead-item:hover { background: var(--azam-blue-tint); }
/* The chosen device, as the register knows it. */
.device-card { border: 1px solid var(--gray-200); border-radius: 12px; padding: 12px 14px; display: grid; gap: 8px; }
.device-card-head { display: flex; gap: 10px; align-items: baseline; }
.device-card-head b { font-size: 15px; color: var(--navy-900); }
.device-card-head span { color: var(--gray-500); font-size: 13px; }
.device-card dl { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px 16px; margin: 0; }
.device-card dt { color: var(--gray-500); font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; }
.device-card dd { margin: 2px 0 0; font-weight: 700; color: var(--gray-900); }
/* Replacement approvals: a check that is not met, and the decision forms side by side. */
.rules .fail>svg { color: var(--red-600, #d92d20); }
.approval-decision { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; padding: 6px 18px 18px; }
.approval-decision form { display: flex; flex-direction: column; gap: 10px; padding: 12px; border-radius: 10px; border: 1px solid rgba(127, 140, 160, .2); }
.approval-decision .button { align-self: flex-start; }
@media (max-width: 900px) { .approval-decision { grid-template-columns: 1fr; } .approval-grid { grid-template-columns: 1fr; } }
/* STB checks on intake: a ring per check, coloured by its outcome. */
.check-ring.pending { color: #8a94a6; background: #8a94a626; }
.check-ring.pending svg { opacity: .35; }
.check-ring.warn { color: #f5b454; background: #f5b45452; }
.check-ring.fail { color: #ff8a7a; background: #ff8a7a52; }
.chk-subject { display: block; margin-top: 2px; font-size: 12px; opacity: .7; }
.chk-badge { min-width: 92px; justify-content: center; }
/* The STB checks banner under the step bar on intake. Light colours first, dark overrides after. */
.stb-flash { margin: 0 0 18px; padding: 14px 18px; animation: stb-flash-in .25s ease-out; }
@keyframes stb-flash-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.stb-flash-top { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.stb-flash-title b { font-size: 15px; margin-right: 8px; }
.stb-flash .chk-verdict { flex: 1; min-width: 240px; }
.stb-flash-checks { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; margin-top: 12px; }
.stb-check { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px; border-radius: 10px; background: rgba(127, 140, 160, .08); border: 1px solid rgba(127, 140, 160, .16); }
.stb-check b { display: block; font-size: 13px; }
.stb-check small { display: block; margin-top: 2px; font-size: 12px; opacity: .75; }
.stb-check .check-ring { flex: none; }
.stb-flash-foot { margin-top: 10px; font-size: 11.5px; opacity: .6; }
@media (max-width: 1000px) { .stb-flash-checks { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .stb-flash-checks { grid-template-columns: 1fr; } }
.chk-verdict { padding: 9px 12px; border-radius: 10px; font-weight: 700; font-size: 13px; border: 1px solid transparent; }
.chk-verdict.ok { color: #0f7a4f; background: #1e9e6a14; border-color: #1e9e6a55; }
.chk-verdict.warn { color: #8a5200; background: #f7900914; border-color: #f7900966; }
.chk-verdict.fail { color: #b42318; background: #d92d2012; border-color: #d92d2055; }
.chk-verdict.pending { color: #5b6473; background: #8a94a614; border-color: #8a94a633; font-weight: 400; }
:root[data-theme="dark"] .chk-verdict.ok { color: #5fd3a0; background: #1e9e6a1f; }
:root[data-theme="dark"] .chk-verdict.warn { color: #f5b454; }
:root[data-theme="dark"] .chk-verdict.fail { color: #ff8a7a; background: #d92d201a; }
:root[data-theme="dark"] .chk-verdict.pending { color: #8a94a6; }
/* A button that reads as a link inside help text, e.g. "Show all centres". */
.link-button { background: none; border: 0; padding: 0; font: inherit; color: inherit; text-decoration: underline; cursor: pointer; }
.device-cover { margin: 0; font-weight: 700; font-size: 13px; }
.device-cover.ok { color: var(--green-600); }
.device-cover.charge { color: #b26d00; }
.device-cover.blocked { color: #c42b1c; }
.device-open { margin: 0; color: var(--red-600); font-weight: 700; font-size: 13px; }
.customer-devices > span { display: block; color: var(--gray-500); font-size: 12px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .05em; margin-bottom: 6px; }
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }
.device-chip { border: 1px solid var(--gray-300); border-radius: 999px; padding: 6px 12px; background: none;
    color: inherit; font: inherit; font-size: 13px; cursor: pointer; }
.device-chip:hover { border-color: var(--azam-blue); color: var(--azam-blue); }
:root[data-theme="dark"] .typeahead-menu { background: #13233a; border-color: #2a4668; box-shadow: 0 12px 28px rgba(0, 0, 0, .45); }
:root[data-theme="dark"] .typeahead-item b,
:root[data-theme="dark"] .device-card-head b,
:root[data-theme="dark"] .device-card dd { color: #e8eef7; }
:root[data-theme="dark"] .typeahead-item span,
:root[data-theme="dark"] .device-card dt,
:root[data-theme="dark"] .device-card-head span { color: #9db0c9; }
:root[data-theme="dark"] .typeahead-item.active,
:root[data-theme="dark"] .typeahead-item:hover { background: rgba(136, 206, 238, .12); }
:root[data-theme="dark"] .typeahead-item em { color: #7cc4f0; }
:root[data-theme="dark"] .device-card { border-color: #2a4668; background: rgba(15, 28, 48, .5); }
:root[data-theme="dark"] .device-cover.ok { color: #5fd3a0; }
:root[data-theme="dark"] .device-cover.charge { color: #f5b454; }
:root[data-theme="dark"] .device-cover.blocked { color: #ff8a7a; }
:root[data-theme="dark"] .device-chip { border-color: #2c4869; }

.template-link { font-weight: 800; color: var(--azam-blue, #0072bc); text-decoration: underline; }
:root[data-theme="dark"] .template-link { color: #7cc4f0; }

/* Audit action badges: one colour per meaning, readable on both themes. Slightly larger than
   the stock badge, since the action is what a reader scans the log for. */
.badge.audit-green, .badge.audit-blue, .badge.audit-amber, .badge.audit-red, .badge.audit-neutral {
    font-size: 11px; padding: 4px 10px; border: 1px solid transparent; }
.badge.audit-green   { background: var(--green-100); color: var(--green-600); border-color: rgba(30, 158, 106, .25); }
.badge.audit-blue    { background: var(--azam-blue-tint); color: var(--azam-blue); border-color: rgba(0, 114, 188, .25); }
.badge.audit-amber   { background: var(--gold-100); color: #b26d00; border-color: rgba(247, 144, 9, .3); }
.badge.audit-red     { background: var(--red-100); color: var(--red-600); border-color: rgba(217, 45, 32, .3); }
.badge.audit-neutral { background: var(--gray-100); color: var(--gray-700); border-color: var(--gray-200); }
:root[data-theme="dark"] .badge.audit-green   { background: rgba(34, 197, 94, .14);  color: #5fd3a0; border-color: rgba(95, 211, 160, .35); }
:root[data-theme="dark"] .badge.audit-blue    { background: rgba(68, 166, 213, .16); color: #7cc4f0; border-color: rgba(124, 196, 240, .35); }
:root[data-theme="dark"] .badge.audit-amber   { background: rgba(247, 144, 9, .15);  color: #f5b454; border-color: rgba(245, 180, 84, .35); }
:root[data-theme="dark"] .badge.audit-red     { background: rgba(237, 28, 36, .16);  color: #ff8f95; border-color: rgba(255, 143, 149, .35); }
:root[data-theme="dark"] .badge.audit-neutral { background: rgba(157, 176, 201, .12); color: #c9d6e8; border-color: rgba(157, 176, 201, .3); }

/* Map pin beside a centre's city; the map opens in a pop-up. */
.city-with-map { display: inline-flex; align-items: center; gap: 6px; }
.map-pin-btn { display: inline-grid; place-items: center; width: 26px; height: 26px; padding: 0;
    border-radius: 7px; border: 1px solid var(--gray-300); background: none; color: var(--azam-blue);
    cursor: pointer; flex: none; }
.map-pin-btn:hover { background: var(--azam-blue-tint); border-color: var(--azam-blue); }
.map-modal-canvas { height: min(460px, 60vh); width: 100%; border-radius: 10px; }
:root[data-theme="dark"] .map-pin-btn { border-color: #2c4869; color: #7cc4f0; }
:root[data-theme="dark"] .map-pin-btn:hover { background: rgba(124, 196, 240, .12); }

/* A proof document shown inside its pop-up. */
.doc-viewer { display: grid; gap: 10px; }
.doc-viewer-bar { display: flex; align-items: center; gap: 12px; }
.doc-viewer-bar b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#doc-viewer-img { display: block; max-width: 100%; max-height: 65vh; margin: 0 auto; border-radius: 8px;
    object-fit: contain; background: repeating-conic-gradient(#0001 0 25%, transparent 0 50%) 0 0 / 16px 16px; }
#doc-viewer-pdf { width: 100%; height: 65vh; border: 0; border-radius: 8px; background: #fff; }
#doc-viewer-img[hidden], #doc-viewer-pdf[hidden] { display: none; }

/* A centre with no location yet: its pin is amber, to be placed. */
.map-pin-btn.map-pin-missing { color: #b26d00; border-style: dashed; }
:root[data-theme="dark"] .map-pin-btn.map-pin-missing { color: #f5b454; }
.map-modal-foot { align-items: center; }
.map-modal-foot #map-pin-status { margin-right: auto; color: var(--gray-500); font-size: 13px; }
:root[data-theme="dark"] .map-modal-foot #map-pin-status { color: #9db0c9; }

/* The map pop-up opens above the centre form when picking a location from it. */
#map-modal { z-index: 70; }
.map-field { display: flex; gap: 8px; align-items: center; }
.map-field .input { flex: 1 1 auto; min-width: 0; }
.map-field .button { flex: none; white-space: nowrap; }
/* Address search above the map. */
.map-search { display: flex; gap: 8px; margin-bottom: 8px; }
.map-search .input { flex: 1 1 auto; }
.map-search-results { display: grid; gap: 2px; margin-bottom: 8px; padding: 6px; border-radius: 10px;
    border: 1px solid var(--gray-200); color: var(--gray-700); font-size: 13px; }
.map-search-item { text-align: left; padding: 7px 9px; border: 0; border-radius: 7px; background: none;
    color: inherit; font: inherit; cursor: pointer; }
.map-search-item:hover { background: var(--azam-blue-tint); }
:root[data-theme="dark"] .map-search-results { border-color: #2a4668; color: #c9d6e8; }
:root[data-theme="dark"] .map-search-item:hover { background: rgba(124, 196, 240, .12); }
