/* ============================================================
   Signet — IC Online Validation System — Brand Tokens
   Drop-in for Signet.Web/wwwroot/css/app.css (the starter's index.html
   links this file but the kit does not ship it).

   Colours come from References/brand/signet.svg: the tile runs
   #7b0d0d → #c62828 → #f9a825 and the seal badge is inked #8e0e0e.
   SIGNET_DESIGN.md §2 explains the roles; read it before adding a colour.
   ============================================================ */
:root {
    /* Brand — theme-invariant. Chrome only: header, sidebar, primary
       actions, links, focus. NEVER for a verdict or a status chip. */
    --signet-primary:   #8e0e0e;  /* Seal maroon. Buttons, links, active state */
    --signet-crimson:   #c62828;  /* Tile mid. Gradient end, hover, emphasis */
    --signet-deep:      #7b0d0d;  /* Tile start. Header start, sidebar, dense headings */
    --signet-gold:      #f9a825;  /* Tile end. Accent: active-nav indicator, focus ring, progress */
    --signet-ink:       #2b2523;  /* Body text, warm near-black */
    --signet-surface:   #f7f5f3;  /* Page background, warm off-white */
    --signet-border:    #e6e0dc;  /* Hairlines */
    --signet-border-subtle: rgba(43, 37, 35, 0.08);
    --signet-on-brand:  #ffffff;  /* Text on the brand gradient (header, auth panel); does not flip */

    /* Bridge: Radzen's primary becomes the brand maroon so every Radzen
       component and every var(--rz-primary) in ported code picks it up. */
    --rz-primary: var(--signet-primary);

    /* Radzen's SECONDARY is a saturated pink in light and teal in dark - neither is a Signet
       colour. The standard row actions use ButtonStyle.Secondary for the view (eye) button
       (HarmonyPx §10.3), so an unbridged secondary put a bright pink control on every row of
       every grid. Bridge it to the neutral surface instead: the eye is the SAFE action and
       should not shout louder than Delete. */
    --rz-secondary: var(--sg-surface-2);
    --rz-on-secondary: var(--sg-text);
    --rz-secondary-light: var(--sg-surface-2);
    --rz-secondary-dark: var(--sg-border);

    /* Bridge Radzen's SEMANTIC scale to Signet's (§2.3). Radzen ships its own Material
       success/warning/danger/info; without this the standard row actions and the Refresh
       footer render in Material's palette rather than the one this document defines - a
       Material blue Refresh and a Material red Delete beside a maroon Add. The button
       STYLES stay as HarmonyPx §9.1 prescribes; only the colours become Signet's. */
    --rz-success: var(--sg-success);
    --rz-warning: var(--sg-warning);
    --rz-danger: var(--sg-danger);
    --rz-info: var(--sg-info);

    /* Semantic theme layer (light). These are what flips in dark mode.
       Custom CSS and razor styles reference these, never literals.
       Ported HarmonyHR components arrive using --hr-*; rename them to --sg-*
       on the way in (CLAUDE.md rule 16). */
    --sg-bg: #f7f5f3;
    --sg-surface: #ffffff;
    --sg-surface-2: #faf8f6;
    --sg-text: #2b2523;
    --sg-text-secondary: #6f6763;
    --sg-border: #e6e0dc;
    --sg-primary: #8e0e0e;
    --sg-accent: #f9a825;
    --sg-on-primary: #ffffff;
    --sg-hover: rgba(43, 37, 35, 0.05);

    /* Semantic status — kit defaults, kept distinct from the brand reds by
       lightness and saturation (maroon #8e0e0e vs signal red #dc3545). */
    --sg-success: #198754;
    --sg-warning: #ffc107;
    --sg-danger: #dc3545;
    --sg-info: #0dcaf0;

    /* Verdict tokens — the officer reads these at a gate. They are their own
       tokens so a brand refresh can never change what VALID looks like, and
       they are never the brand maroon or the brand gold. */
    --sg-verdict-valid: #1b7f3b;
    --sg-verdict-valid-bg: #e6f4ea;
    --sg-verdict-invalid: #c62828;   /* signal red, filled — the one place crimson is a status */
    --sg-verdict-invalid-bg: #fdecea;
    --sg-verdict-hold: #b26a00;      /* amber ink, not brand gold */
    --sg-verdict-hold-bg: #fff4e0;

    /* Chart inks. Six categorical hues for a series index, defined here and in the dark block; a mark
       never names a colour, it carries data-i / data-k / data-tone and the palette class resolves
       --mark from one of these. None of them is the brand maroon or the brand gold, and each clears
       3:1 against --sg-surface so a thin line is still a line. */
    --sg-chart-1: #1f6feb;
    --sg-chart-2: #0f7c73;
    --sg-chart-3: #6a3fbd;
    --sg-chart-4: #a1207a;
    --sg-chart-5: #5a6b8c;
    --sg-chart-6: #4a7c26;

    /* Header gradient. Crimson → deep, never to gold: white text needs ≥ 4.5:1
       and white on #f9a825 is 1.9:1. */
    --sg-header-gradient: linear-gradient(90deg, var(--signet-deep) 0%, var(--signet-crimson) 100%);
}

/* Dark theme. Keyed off <html data-theme="dark"> set by js/theme.js and the
   pre-paint boot script in index.html. In dark mode the brand GOLD becomes the
   primary: it is the tile's own third colour, it clears contrast on #121212 with
   dark text, and it never collides with the red danger/invalid signals the way a
   lightened maroon would. */
[data-theme="dark"] {
    color-scheme: dark;

    --sg-bg: #131111;
    --sg-surface: #1e1b1a;
    --sg-surface-2: #292423;
    --sg-text: rgba(255, 255, 255, .87);
    --sg-text-secondary: rgba(255, 255, 255, .60);
    --sg-border: #3b3432;
    --sg-primary: #f9a825;
    --sg-accent: #e57373;
    --sg-on-primary: rgba(0, 0, 0, .87);
    --sg-hover: rgba(255, 255, 255, 0.06);

    --sg-success: #66bb6a;
    --sg-warning: #ffb74d;
    --sg-danger: #ef5350;
    --sg-info: #4fc3f7;

    --sg-verdict-valid: #81c784;
    --sg-verdict-valid-bg: rgba(129, 199, 132, .14);
    --sg-verdict-invalid: #ef5350;
    --sg-verdict-invalid-bg: rgba(239, 83, 80, .14);
    --sg-verdict-hold: #ffb74d;
    --sg-verdict-hold-bg: rgba(255, 183, 77, .14);

    --sg-chart-1: #6ea8fe;
    --sg-chart-2: #4dd0c4;
    --sg-chart-3: #b39ddb;
    --sg-chart-4: #f06292;
    --sg-chart-5: #9fb3cd;
    --sg-chart-6: #a5d16a;

    --sg-header-gradient: linear-gradient(90deg, #4a0808 0%, #8e1b1b 100%);

    --rz-primary: var(--sg-primary);
    --rz-on-primary: rgba(0, 0, 0, .87);

    /* Same secondary bridge as the light block: the eye button follows the surface, not
       Radzen's teal. --rz-on-secondary must be the body text colour here, not near-black,
       or the icon disappears into a dark button. */
    --rz-secondary: var(--sg-surface-2);
    --rz-on-secondary: var(--sg-text);
    --rz-secondary-light: var(--sg-surface-2);
    --rz-secondary-dark: var(--sg-border);

    /* Bridge Radzen's SEMANTIC scale to Signet's (§2.3). Radzen ships its own Material
       success/warning/danger/info; without this the standard row actions and the Refresh
       footer render in Material's palette rather than the one this document defines - a
       Material blue Refresh and a Material red Delete beside a maroon Add. The button
       STYLES stay as HarmonyPx §9.1 prescribes; only the colours become Signet's. */
    --rz-success: var(--sg-success);
    --rz-warning: var(--sg-warning);
    --rz-danger: var(--sg-danger);
    --rz-info: var(--sg-info);
    --rz-text-tertiary-color: rgba(255, 255, 255, .55);
    --rz-text-disabled-color: rgba(255, 255, 255, .42);
}

/* Page canvas follows the semantic theme so the pre-Blazor splash flips too. Radzen styles its own
   components with --rz-text-font-family but leaves plain elements to the browser default (a serif), so the
   canvas takes the same face. */
html, body {
    background-color: var(--sg-bg);
    color: var(--sg-text);
    font-family: var(--rz-text-font-family, Roboto, sans-serif);
}

/* ---------- Shell chrome ---------- */
.rz-header {
    background: var(--sg-header-gradient) !important;
}

.rz-header .rz-label,
.rz-header .rz-link,
.rz-header .rzi,
.rz-header .rz-navigation-item-link,
.rz-header .rz-navigation-item-icon {
    color: #ffffff !important;
}

.rz-header .rz-navigation-item-wrapper:hover {
    background-color: rgba(255, 255, 255, 0.12) !important;
}

.rz-menu {
    background-color: transparent !important;
    border: none !important;
}

.rz-menu .rz-navigation-menu {
    background-color: var(--signet-deep) !important;
}

/* Brand lockup in the header: tile at 28px beside the product name. */
.sg-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
    color: #ffffff;
    text-decoration: none;
}

.sg-brand img {
    width: 28px;
    height: 28px;
    border-radius: 6px;
    display: block;
}

.sg-brand .sg-brand-name {
    font-weight: 600;
    letter-spacing: 0.2px;
    white-space: nowrap;
}

/* Sidebar: warm surface, gold indicator on the active leaf. */
.rz-sidebar {
    background-color: var(--sg-surface);
    border-right: 1px solid var(--sg-border);
}

.rz-panel-menu .rz-navigation-item-wrapper:hover {
    background-color: var(--sg-hover) !important;
}

.rz-panel-menu .rz-navigation-item-link.rz-navigation-item-link-active,
.rz-panel-menu .rz-navigation-item-wrapper-active {
    box-shadow: inset 3px 0 0 var(--signet-gold);
    color: var(--sg-primary) !important;
}

/* Sidebar menu (Layout/NavMenu.razor + NavMenuItem.razor): icon slot fixed and aligned as in HarmonyHR, labels ellipsised
   instead of colliding with the expand chevron, search box on the secondary surface. Icons are Material Symbols names
   from Modules.ImageUrl (the module workbook). */
.nav-scrollable {
    height: calc(100vh - 3.5rem);
    overflow-y: auto;
}

.search-container {
    padding: 8px;
    background-color: var(--sg-surface-2);
    border-bottom: 1px solid var(--sg-border);
}

.rz-panel-menu {
    padding: 0;
}

.rz-panel-menu .rz-navigation-item-wrapper {
    line-height: 1.25rem;
}

.rz-panel-menu .rz-navigation-item-icon {
    margin-right: 0.5rem;
    width: 1.25rem;
    height: 1.25rem;
    font-size: 1.25rem;
    flex: 0 0 1.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.rz-panel-menu .rz-navigation-item-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---- Home (module 03): the landing page and the role dashboards. ----
   The dashboard is a frame of fourteen fixed slots in four bands, and every dashboard fills all of them; a
   slot the procedure sent nothing for renders a placeholder at full size rather than collapsing, so the same
   slot means the same kind of thing on every role's page. Each band is its own twelve-column grid with the
   same gap, so the bands line up while a band can still reorder its own children at a narrow width.

   The widths answer the DASHBOARD's own width (container queries on .sg-dash), not the window's: opening the
   sidebar changes the room a dashboard has and the viewport does not know it. ---- */
.sg-home-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; flex-wrap: wrap; }
.sg-home-chip { display: inline-flex; align-items: center; gap: .35rem; border: 1px solid var(--tone, var(--sg-text-secondary)); color: var(--tone, var(--sg-text-secondary)); background: transparent; border-radius: 999px; padding: .2rem .7rem; font-size: .8rem; font-weight: 600; cursor: pointer; }
.sg-home-chip--good { --tone: var(--sg-success); }
.sg-home-chip--warn { --tone: var(--sg-warning); }
.sg-home-chip--bad { --tone: var(--sg-danger); }
.sg-home-chip--info { --tone: var(--sg-info); }
.sg-home-chip:focus-visible { outline: 2px solid var(--signet-gold); outline-offset: 2px; }

/* Band 5: exactly three advisory cards in the same twelve-column rhythm as the dashboard above them. */
.sg-advisories { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: .75rem; }
.sg-advisories > * { grid-column: span 4; min-width: 0; }
.sg-advisory { background: var(--sg-surface); border: 1px solid var(--sg-border); border-left: 4px solid var(--tone, var(--sg-info)); border-radius: .5rem; padding: .75rem .9rem; display: flex; flex-direction: column; gap: .2rem; min-height: 6.5rem; }
.sg-advisory--good { --tone: var(--sg-success); }
.sg-advisory--warn { --tone: var(--sg-warning); }
.sg-advisory--bad { --tone: var(--sg-danger); }
.sg-advisory--info { --tone: var(--sg-info); }
.sg-advisory--none { border-left-color: var(--sg-border); color: var(--sg-text-secondary); align-items: center; justify-content: center; text-align: center; }
.sg-advisory__head { display: flex; align-items: center; gap: .4rem; min-width: 0; }
.sg-advisory__head .rz-icon { color: var(--tone, var(--sg-info)); font-size: 1.1rem; flex: 0 0 auto; }
.sg-advisory__title { font-weight: 600; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.sg-advisory__body { font-size: .84rem; color: var(--sg-text); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }
.sg-advisory__date { font-size: .75rem; color: var(--sg-text-secondary); font-variant-numeric: tabular-nums; margin-top: auto; }
.sg-advisories__more { display: flex; justify-content: flex-end; }

/* Tone tokens for everything inside a dashboard. A tone is never a brand colour and never a verdict ink. */
.sg-dashboard { --sg-tone-neutral: var(--sg-text-secondary); --sg-tone-good: var(--sg-success); --sg-tone-warn: var(--sg-warning); --sg-tone-bad: var(--sg-danger); --sg-tone-info: var(--sg-info); display: flex; flex-direction: column; gap: 1rem; container-type: inline-size; container-name: dashboard; }

/* minmax(0, 1fr), never 1fr: `1fr` means minmax(auto, 1fr), so the right track could not shrink below the
   tools' min-content while the left one could (the title ellipsises). Unequal tracks put the "centre" column
   off the header's centre line by 19-70px, which is invisible to the eye and obvious to a probe. */
.sg-dashhead { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: .75rem; }
.sg-dashhead__titles { min-width: 0; display: flex; flex-direction: column; gap: .1rem; }
.sg-dashhead__titles h1 { overflow: hidden; text-overflow: ellipsis; }
.sg-dashhead__subtitle { font-size: .82rem; color: var(--sg-text-secondary); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.sg-dashhead__lens { display: flex; justify-content: center; min-width: 0; }
/* min-width:0 and overflow:hidden, because minmax(0, 1fr) lets this track be narrower than its content and
   the content is nowrap and right-aligned: without these it spills LEFT, and the as-of date lands on top of
   the lens switch by 54.7px. Nothing scrolls when it happens, so no probe that watches for scroll can see it.
   The as-of is the designated thing to give (its full date is already on its title attribute) - the period
   switch and PRINT stay whole, which is the G2 rule. */
.sg-dashhead__tools { display: flex; align-items: center; justify-content: flex-end; gap: .4rem; flex-wrap: nowrap; flex: 0 0 auto; min-width: 0; overflow: hidden; }
.sg-dashhead__tools .rz-button { flex: 0 0 auto; }
.sg-dashhead__asof { font-size: .76rem; color: var(--sg-text-secondary); white-space: nowrap; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* The Note is a standing sentence about scope, not an event: one slim line, not a sixty-pixel alert. */
.sg-dashnote { display: flex; align-items: center; gap: .4rem; padding: .3rem .6rem; border-radius: .4rem; background: var(--sg-surface-2); border: 1px solid var(--sg-border); color: var(--sg-text-secondary); font-size: .8rem; }
.sg-dashnote .rz-icon { color: var(--sg-info); font-size: 1rem; flex: 0 0 auto; }
.sg-dashnote > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* F1: the tab panel's own padding narrowed the dashboard by ~32px and dropped it a tier. */
.sg-dashtabs .rz-tabview-panels, .sg-dashtabs .rz-tabview-panel { padding-left: 0; padding-right: 0; }
.sg-dashtabs .rz-tabview-panel { padding-top: .75rem; }
/* Below the width where even a title of nothing leaves room for both, the lens takes a row of its own -
   still CENTRED, because the switch is in the same place on every dashboard whichever row it is on. */
/* The lens takes a row of its own - still centred - once it no longer fits a third of the header. Three or
   more lenses reach that point at about 1100px, which is what a dashboard has at 1366 inside the Home tabs;
   one or two reach it much later. The component says which it is, because CSS cannot count them. */
@container dashboard (max-width: 1100px) {
    .sg-dashhead--many-lenses { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "title tools" "lens lens"; row-gap: .5rem; }
    .sg-dashhead--many-lenses .sg-dashhead__titles { grid-area: title; }
    .sg-dashhead--many-lenses .sg-dashhead__tools { grid-area: tools; }
    .sg-dashhead--many-lenses .sg-dashhead__lens { grid-area: lens; justify-content: center; }
}
@container dashboard (max-width: 820px) {
    .sg-dashhead { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "title tools" "lens lens"; row-gap: .5rem; }
    .sg-dashhead__titles { grid-area: title; }
    .sg-dashhead__tools { grid-area: tools; }
    .sg-dashhead__lens { grid-area: lens; justify-content: center; }
}
@media (max-width: 640px) { .sg-dashhead__tools { flex-wrap: wrap; justify-content: flex-start; } }

/* ---- The frame ---- */
.sg-dash { container-type: inline-size; container-name: dash; display: flex; flex-direction: column; gap: .75rem; }
.sg-dash__band { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: .75rem; }
.sg-dash__slot { min-width: 0; overflow: hidden; }
.sg-dash__band--pulse { grid-auto-rows: 136px; }
.sg-dash__band--pulse > .sg-dash__slot { grid-column: span 2; }
.sg-dash__band--picture { grid-auto-rows: 320px; }
.sg-dash__band--picture > [data-slot="FL"], .sg-dash__band--picture > [data-slot="FR"] { grid-column: span 3; }
.sg-dash__band--picture > [data-slot="H"] { grid-column: span 6; }
.sg-dash__band--work { grid-auto-rows: minmax(200px, auto); }
.sg-dash__band--work > .sg-dash__slot { grid-column: span 6; }
.sg-dash__band--breakdown { grid-auto-rows: minmax(300px, auto); }
/* Only a BARS list may push the Breakdown band taller. A plot's <svg> has no intrinsic height, so once the row
   became auto-sized it fell back to its viewBox aspect - a square as wide as the card - and one columns chart
   inflated the whole band, dragging the two cards beside it to the same height with two thirds of each empty.
   A plot in a B slot therefore has a FIXED height, the one it had when the band was a flat 300px. The Picture
   band cannot do this because its rows are fixed at every tier. The round marks are named for the same reason
   and not a different one: the mechanism is the SVG, not the chart kind. */
.sg-dash__band--breakdown .sg-plot,
.sg-dash__band--breakdown .sg-round { height: 176px; flex: 0 0 auto; }
.sg-dash__band--breakdown > .sg-dash__slot { grid-column: span 4; }

/* Tier (b): still two-dimensional, never an odd split. Six tiles become 3x2; the hero takes its own row
   above its two round marks (DOM order is FL H FR, so the hero is pulled up rather than the marks pushed). */
@container dash (max-width: 899px) {
    .sg-dash__band--pulse > .sg-dash__slot { grid-column: span 4; }
    .sg-dash__band--picture > [data-slot="H"] { grid-column: span 12; order: -1; }
    .sg-dash__band--picture > [data-slot="FL"], .sg-dash__band--picture > [data-slot="FR"] { grid-column: span 6; }
    .sg-dash__band--picture { grid-auto-rows: 260px; }
    .sg-dash__band--pulse { grid-auto-rows: 144px; }
}
/* Tier (c): two tiles across, everything else full width. */
@container dash (max-width: 639px) {
    .sg-dash__band--pulse > .sg-dash__slot { grid-column: span 6; }
    .sg-dash__band--picture > .sg-dash__slot,
    .sg-dash__band--work > .sg-dash__slot,
    .sg-dash__band--breakdown > .sg-dash__slot { grid-column: span 12; }
}

/* Card chrome, shared by every slot so the bands read as one surface. */
.sg-kpi, .sg-chart, .sg-work, .sg-slot-empty { background: var(--sg-surface); border: 1px solid var(--sg-border); border-radius: .5rem; color: var(--sg-text); display: flex; flex-direction: column; }
.sg-slot-empty { align-items: center; justify-content: center; gap: .3rem; border-style: dashed; color: var(--sg-text-secondary); padding: .5rem; text-align: center; }
.sg-slot-empty__icon { font-size: 1.3rem; opacity: .7; }
.sg-slot-empty__text { font-size: .8rem; }

/* ---- Band 1: the KPI tiles ---- */
.sg-kpi { --tone: var(--sg-tone-neutral); border-left: 4px solid var(--tone); padding: .5rem .8rem; gap: .1rem; justify-content: flex-start; }
.sg-kpi--good { --tone: var(--sg-tone-good); }
.sg-kpi--warn { --tone: var(--sg-tone-warn); }
.sg-kpi--bad { --tone: var(--sg-tone-bad); }
.sg-kpi--info { --tone: var(--sg-tone-info); }
.sg-kpi--link { cursor: pointer; transition: background-color .15s ease, box-shadow .15s ease; }
.sg-kpi--link:hover { background: var(--sg-hover); box-shadow: 0 1px 4px rgba(0, 0, 0, .12); }
.sg-kpi--link:focus-visible { outline: 2px solid var(--signet-gold); outline-offset: 2px; }
.sg-kpi__head { display: flex; align-items: center; gap: .35rem; color: var(--sg-text-secondary); font-size: .74rem; letter-spacing: .01em; text-transform: uppercase; min-width: 0; }
.sg-kpi__icon { color: var(--tone); font-size: 1.05rem; flex: 0 0 auto; }
.sg-kpi__label { overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.15; }
.sg-kpi__figure { display: flex; align-items: baseline; gap: .4rem; min-width: 0; flex: 0 0 auto; }
.sg-kpi__value { font-size: 1.5rem; font-weight: 600; line-height: 1.1; font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.sg-kpi__trace { height: 20px; flex: 0 0 auto; }
/* The sentence that makes the figure mean something. It was a tooltip, so on a page nobody hovers it did not exist. */
.sg-kpi__hint { font-size: .72rem; line-height: 1.15; color: var(--sg-text-secondary); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; margin-top: auto; }
/* No sparkline above it, so the hint may have the empty row: two lines hold about 56 characters here. */
.sg-kpi__hint--roomy { -webkit-line-clamp: 3; }
.sg-delta { --tone: var(--sg-tone-neutral); display: inline-flex; align-items: center; gap: .1rem; color: var(--tone); font-size: .74rem; font-weight: 600; white-space: nowrap; flex: 0 0 auto; }
.sg-delta--good { --tone: var(--sg-tone-good); }
.sg-delta--warn { --tone: var(--sg-tone-warn); }
.sg-delta--bad { --tone: var(--sg-tone-bad); }
.sg-delta--info { --tone: var(--sg-tone-info); }
.sg-delta__glyph { font-size: .9rem; }
.sg-spark { width: 100%; height: 100%; display: block; }
.sg-spark__line { fill: none; stroke: var(--tone, var(--sg-text-secondary)); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.sg-spark__area { fill: var(--tone, var(--sg-text-secondary)); opacity: .12; stroke: none; }

/* ---- Bands 2 and 4: the chart cards ---- */
.sg-chart { padding: .6rem .8rem .5rem; gap: .35rem; }
.sg-chart__head { display: flex; align-items: flex-start; justify-content: space-between; gap: .5rem; min-width: 0; }
.sg-chart__titles { display: flex; flex-direction: column; min-width: 0; }
.sg-chart__title { font-size: .9rem; font-weight: 600; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.sg-chart__link { flex: 0 0 auto; min-width: 0; padding: .1rem; }
.sg-chart__subtitle { font-size: .76rem; color: var(--sg-text-secondary); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.sg-chart__empty { flex: 1 1 auto; display: flex; align-items: center; justify-content: center; text-align: center; color: var(--sg-text-secondary); font-size: .82rem; padding: .5rem; }
.sg-chart__figure { margin: 0; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: .3rem; }
.sg-chart__caption { display: flex; align-items: center; justify-content: center; gap: .5rem; flex-wrap: wrap; flex: 0 0 auto; }
/* The sentence under an empty gauge: why there is nothing to measure. */
.sg-chart__note { font-size: .72rem; color: var(--sg-text-secondary); text-align: center; overflow-wrap: anywhere; }
.sg-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .1rem .7rem; justify-content: center; }
.sg-legend__item { display: inline-flex; align-items: center; gap: .3rem; font-size: .74rem; color: var(--sg-text-secondary); min-width: 0; }
.sg-legend__swatch { width: .6rem; height: .6rem; border-radius: 2px; background: var(--mark, var(--sg-text-secondary)); flex: 0 0 auto; }
.sg-legend__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 12rem; }
/* A round mark sits on a span-3 card and its slices carry the seeded vocabulary's own wording, which runs to
   twenty characters ("PARTIAL MATCH - HOLD"). Wrapped chips would take an unpredictable number of lines out of
   a card whose height the grid fixes; one entry per line is deterministic - N slices, N lines - and each label
   clamps to the card with its full text on title= and in the hidden table. */
.sg-chart--donut .sg-legend { flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: .05rem; }
.sg-chart--donut .sg-legend__item { width: 100%; }
.sg-chart--donut .sg-legend__label { max-width: none; flex: 1 1 auto; }

/* The screen-reader table under every chart. Also what a browser smoke reads, so it is never display:none. */
/* Visually hidden, and hidden from the LAYOUT too. This must be applied to a block box: a <table> under
   table-layout:auto treats width:1px as a suggestion and sizes to its content, and `clip` only stops the
   painting - the box still counts towards an ancestor's scrollable overflow, which made every dashboard
   scroll sideways on a table nobody could see. The chart's table is wrapped in a div carrying this class and
   stays a real table underneath, so a screen reader still reads it as one. */
.sg-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; border: 0; table-layout: fixed; }
.sg-sr-only table { table-layout: fixed; width: 1px; }
/* A <caption> inherits the nowrap above and sets a floor of its own - 309px, measured - which table-layout
   does not reach, so a 240px flank card still scrolled by 68px. It must be allowed to wrap. */
.sg-sr-only caption, .sg-sr-only table caption { white-space: normal; overflow-wrap: anywhere; }

/* Plots: the marks are SVG stretched to the card, every label is HTML beside it. */
.sg-plot { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; column-gap: .4rem; row-gap: .2rem; }
.sg-plot__ticks { grid-column: 1; grid-row: 1; display: flex; flex-direction: column; justify-content: space-between; align-items: flex-end; font-size: .68rem; color: var(--sg-text-secondary); font-variant-numeric: tabular-nums; }
.sg-plot__svg { grid-column: 2; grid-row: 1; width: 100%; height: 100%; display: block; overflow: visible; }
.sg-plot__cats { grid-column: 2; grid-row: 2; font-size: .68rem; color: var(--sg-text-secondary); }
/* A trend's labels are placed at their own points (inline left:%), because the printed subset of thirty daily
   buckets is not evenly spaced and space-between would put a label under the wrong day. */
.sg-plot__cats--points { display: block; position: relative; height: 1.1em; }
.sg-plot__cats--points > .sg-plot__cat { position: absolute; transform: translateX(-50%); max-width: 6rem; }
.sg-plot__cats--points > .sg-plot__cat:first-child { transform: none; }
.sg-plot__cats--points > .sg-plot__cat:last-child { transform: translateX(-100%); }
.sg-plot__cat { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sg-plot__rule { stroke: var(--sg-border); stroke-width: 1; vector-effect: non-scaling-stroke; }
.sg-plot__line { fill: none; stroke: var(--mark, var(--sg-text-secondary)); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.sg-plot__area { fill: var(--mark, var(--sg-text-secondary)); opacity: .14; stroke: none; }
.sg-plot__bar { fill: var(--mark, var(--sg-text-secondary)); }
/* A threshold drawn across a column plot (B2's 100%): a rule, never a series, so it takes the text ink. */
.sg-plot__target { stroke: var(--sg-text); stroke-width: 1.5; stroke-dasharray: 4 3; opacity: .7; vector-effect: non-scaling-stroke; }

/* Bars are HTML rows: a party name has to wrap and ellipsise like text, which SVG text does not. */
/* The label sits ABOVE its bar and takes the whole card: these labels are sentences (a refusal reason runs
   to 200 characters), and five of them in a fixed 7rem column all read "Check 4 failed: the...". Rows stack
   from the TOP, so one bar sits under the title instead of floating in the middle of the card. */
.sg-bars { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; justify-content: flex-start; gap: .3rem; }
.sg-bars__row { display: flex; flex-direction: column; gap: .1rem; font-size: .76rem; min-width: 0; flex: 0 0 auto; }
.sg-bars__line { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: .45rem; }
.sg-bars__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--sg-text); }
.sg-bars__track { position: relative; height: .7rem; background: var(--sg-surface-2); border: 1px solid var(--sg-border); border-radius: 999px; overflow: hidden; }
.sg-bars__fill { position: absolute; inset: 0 auto 0 0; background: var(--mark, var(--sg-text-secondary)); border-radius: 999px; }
.sg-bars__target { position: absolute; top: -2px; bottom: -2px; width: 2px; background: var(--sg-text); opacity: .65; }
.sg-bars__value { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }

/* Round marks keep their aspect ratio: a circle drawn under preserveAspectRatio="none" is an ellipse. */
.sg-round { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.sg-round__svg { width: 100%; height: 100%; max-height: 100%; display: block; }
.sg-round__track { fill: none; stroke: var(--sg-surface-2); stroke-width: 14; }
.sg-round__slice { fill: none; stroke: var(--mark, var(--sg-text-secondary)); stroke-width: 14; transform: rotate(-90deg); transform-origin: 50% 50%; }
.sg-round__svg--gauge .sg-round__track, .sg-round__reading { fill: none; stroke-width: 10; stroke-linecap: butt; }
.sg-round__reading { stroke: var(--mark, var(--sg-text-secondary)); }
.sg-round__notch { fill: var(--sg-text); }
.sg-round__centre { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .1rem; pointer-events: none; text-align: center; padding: 0 12%; }
.sg-round__centre--gauge { justify-content: center; padding-top: 12%; }
.sg-round__figure { font-size: 1.35rem; font-weight: 600; line-height: 1.1; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.sg-round__caption { font-size: .72rem; color: var(--sg-text-secondary); overflow-wrap: anywhere; }
/* A grid of three, never a flex row: the middle cell used to ride over the numbers beside it. */
.sg-round__ends { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: baseline; width: 100%; gap: .5rem; font-size: .68rem; color: var(--sg-text-secondary); font-variant-numeric: tabular-nums; }
.sg-round__end { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.sg-round__end--min { text-align: left; }
.sg-round__end--mid { text-align: center; font-style: italic; }
.sg-round__end--max { text-align: right; }

/* ---- Band 3: the two work lists ---- */
.sg-work { padding: .6rem .8rem; gap: .35rem; }
.sg-work__head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; min-width: 0; }
.sg-work__title { display: flex; align-items: center; gap: .4rem; min-width: 0; }
.sg-work__name { font-size: .9rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sg-work__count { font-size: .72rem; font-weight: 600; color: var(--sg-text-secondary); border: 1px solid var(--sg-border); border-radius: 999px; padding: 0 .45rem; flex: 0 0 auto; }
.sg-work__empty { flex: 1 1 auto; display: flex; align-items: center; justify-content: center; text-align: center; color: var(--sg-text-secondary); font-size: .82rem; min-height: 4rem; }
.sg-work__list { list-style: none; margin: 0; padding: 0; flex: 0 0 auto; display: flex; flex-direction: column; }
/* flex 0 0 auto, NOT 1 1 0: a stretched row made a one-row list a single hover block the height of the card. */
.sg-work__row { display: flex; justify-content: space-between; align-items: flex-start; gap: .6rem; padding: .35rem 0; border-top: 1px solid var(--sg-border); min-width: 0; flex: 0 0 auto; }
.sg-work__row:first-child { border-top: 0; }
.sg-work__row--link { cursor: pointer; }
.sg-work__row--link:hover { background: var(--sg-hover); }
.sg-work__row--link:focus-visible { outline: 2px solid var(--signet-gold); outline-offset: -2px; }
.sg-work__main { min-width: 0; flex: 1 1 auto; }
.sg-work__row-title { font-size: .84rem; font-weight: 500; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.sg-work__row-subtitle { font-size: .76rem; color: var(--sg-text-secondary); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
/* The badge is a short word and never shrinks: it was clipped to "Ref...", "DE..." while the subtitle
   beside it had room. The main column takes whatever is left. */
.sg-work__side { display: flex; flex-direction: column; align-items: flex-end; gap: .15rem; flex: 0 0 auto; }
.sg-work__date { font-size: .72rem; color: var(--sg-text-secondary); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---- The two segmented switches ---- */
/* A segmented control never shrinks. Four lenses inside the Home tabs crushed the period switch to two
   slivers reading "1 3 1" and clipped PRINT to "PRIN": the controls were shrinkable and the title was not,
   so the wrong thing gave. The title gives now; these keep their natural width. */
.sg-seg { display: inline-flex; border: 1px solid var(--sg-border); border-radius: 999px; background: var(--sg-surface-2); padding: 2px; gap: 2px; flex: 0 0 auto; }
.sg-seg__btn { display: inline-flex; align-items: center; gap: .3rem; border: 0; background: transparent; color: var(--sg-text-secondary); font: inherit; font-size: .78rem; font-weight: 600; padding: .2rem .7rem; border-radius: 999px; cursor: pointer; white-space: nowrap; flex: 0 0 auto; min-width: max-content; }
.sg-seg__btn:hover { background: var(--sg-hover); color: var(--sg-text); }
.sg-seg__btn:focus-visible { outline: 2px solid var(--signet-gold); outline-offset: 1px; }
.sg-seg__btn--on { background: var(--sg-surface); color: var(--sg-text); box-shadow: 0 1px 2px rgba(0, 0, 0, .12); }
.sg-seg__icon { font-size: 1rem; }
.sg-seg__text { white-space: nowrap; }

/* ---- Palettes. A mark carries data-i / data-k / data-tone; the class on the card decides which one paints. ---- */
.sg-pal--categorical [data-i="1"] { --mark: var(--sg-chart-1); }
.sg-pal--categorical [data-i="2"] { --mark: var(--sg-chart-2); }
.sg-pal--categorical [data-i="3"] { --mark: var(--sg-chart-3); }
.sg-pal--categorical [data-i="4"] { --mark: var(--sg-chart-4); }
.sg-pal--categorical [data-i="5"] { --mark: var(--sg-chart-5); }
.sg-pal--categorical [data-i="6"] { --mark: var(--sg-chart-6); }
.sg-pal--tone [data-tone="neutral"] { --mark: var(--sg-tone-neutral); }
.sg-pal--tone [data-tone="good"] { --mark: var(--sg-tone-good); }
.sg-pal--tone [data-tone="warn"] { --mark: var(--sg-tone-warn); }
.sg-pal--tone [data-tone="bad"] { --mark: var(--sg-tone-bad); }
.sg-pal--tone [data-tone="info"] { --mark: var(--sg-tone-info); }
.sg-pal--status [data-k="IN_FORCE"] { --mark: var(--sg-success); }
.sg-pal--status [data-k="EXPIRED"] { --mark: var(--sg-text-secondary); }
.sg-pal--status [data-k="CANCELLED"] { --mark: var(--sg-danger); }
.sg-pal--status [data-k="DRAWN"] { --mark: var(--sg-warning); }
.sg-pal--status [data-k="CONSUMED"] { --mark: var(--sg-info); }
/* A tone is never a verdict ink, but a series that COUNTS verdicts is the verdict and takes the section 2.4 inks. */
.sg-pal--verdict [data-k="VALID"] { --mark: var(--sg-verdict-valid); }
.sg-pal--verdict [data-k="PARTIAL_MATCH"] { --mark: var(--sg-verdict-hold); }
.sg-pal--verdict [data-k="NOT_VALID"] { --mark: var(--sg-verdict-invalid); }

/* Badges on a work row and anywhere else a tone is spelled out. */
.sg-badge { --tone: var(--sg-tone-neutral); display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; font-size: .72rem; font-weight: 600; letter-spacing: .02em; padding: .1rem .5rem; border-radius: 999px; border: 1px solid var(--tone); color: var(--tone); white-space: nowrap; }
.sg-badge--good { --tone: var(--sg-tone-good); }
.sg-badge--warn { --tone: var(--sg-tone-warn); }
.sg-badge--bad { --tone: var(--sg-tone-bad); }
.sg-badge--info { --tone: var(--sg-tone-info); }
.sg-work__side .sg-badge { flex: 0 0 auto; max-width: none; overflow: visible; }
.sg-section__empty { color: var(--sg-text-secondary); margin: 0; }

/* ---- Idle session countdown chip + session menu (header, authenticated only) ----
   The chip sits on the brand gradient, so its resting state is white on a translucent pill. Under five
   minutes it turns to the warning token, under one minute the danger token — state colours, never brand
   maroon/gold, kept legible on the gradient by a solid light pill behind the coloured text. */
.sg-idle {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    font-variant-numeric: tabular-nums;
    font-size: 0.85rem;
    line-height: 1.4;
    color: #ffffff;
    background: rgba(255, 255, 255, 0.14);
}
.sg-idle .rzi { font-size: 1rem; }
.sg-idle__time { font-weight: 600; letter-spacing: 0.02em; }
.sg-idle--warn { color: var(--sg-warning); background: rgba(255, 255, 255, 0.92); }
.sg-idle--danger { color: var(--sg-danger); background: rgba(255, 255, 255, 0.92); }

.sg-session-menu__name { margin-left: 0.35rem; font-weight: 600; }

/* The header user-menu POPUP is a surface card, not more maroon chrome.
   `.rz-menu .rz-navigation-menu` (above) paints every popup with --signet-deep, and Radzen's default
   item label is a dark grey — dark-grey text on maroon, invisible in light mode (the icons were forced
   white by the .rz-header rule, so only the words vanished). The collapsed trigger stays white-on-maroon
   in the header; the popup that drops out of it becomes an ordinary theme-aware card, the same surface as
   every dropdown and dialog in the app, so it reads in both light and dark. Scoped to .sg-session-menu and
   later in the file, so it wins on order (the background) and on specificity (the label colour). */
.sg-session-menu .rz-navigation-menu {
    background-color: var(--sg-surface) !important;
    border: 1px solid var(--sg-border);
    border-radius: 8px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
    padding: 0.25rem;
    margin-top: 0.25rem;
    min-width: 15rem;
}

.sg-session-menu .rz-navigation-menu .rz-navigation-item-link {
    color: var(--sg-text) !important;
    border-radius: 6px;
}

.sg-session-menu .rz-navigation-menu .rz-navigation-item-icon {
    color: var(--sg-text-secondary) !important;
}

.sg-session-menu .rz-navigation-menu .rz-navigation-item-wrapper:hover,
.sg-session-menu .rz-navigation-menu .rz-navigation-item-link:hover {
    background-color: var(--sg-hover) !important;
}

.sg-session-menu .rz-navigation-menu .rz-navigation-item-wrapper:hover .rz-navigation-item-link,
.sg-session-menu .rz-navigation-menu .rz-navigation-item-wrapper:hover .rz-navigation-item-icon {
    color: var(--sg-text) !important;
}


/* ---- Print (GridTools): the shell goes, the page content fills the sheet. ---- */
@media print {
    .sidebar, .rz-sidebar, .rz-header, .top-row, .sg-no-print, .sg-help-drawer, .rz-notification, .rz-dialog-wrapper, .rz-panel-menu, .search-container { display: none !important; }
    .rz-body, .rz-layout, main, .content, article { margin: 0 !important; padding: 0 !important; width: 100% !important; max-width: none !important; }
    body { background: #ffffff; color: #000000; }
    .rz-data-grid { box-shadow: none !important; border: 1px solid #999999; }
    .rz-paginator, .rz-grid-filter, .rz-cell-filter { display: none !important; }
    a[href]::after { content: none !important; }
    /* A dashboard prints as the full twelve-column frame: the container query would otherwise read the
       sheet as a narrow container and print the phone layout. The switches are controls, not figures. */
    .sg-dash { container-type: normal !important; }
    .sg-seg { display: none !important; }
    .sg-dash__band--pulse > .sg-dash__slot { grid-column: span 2 !important; }
    .sg-dash__band--picture > [data-slot="FL"], .sg-dash__band--picture > [data-slot="FR"] { grid-column: span 3 !important; order: 0 !important; }
    .sg-dash__band--picture > [data-slot="H"] { grid-column: span 6 !important; order: 0 !important; }
    .sg-dash__band--work > .sg-dash__slot { grid-column: span 6 !important; }
    .sg-dash__band--breakdown > .sg-dash__slot { grid-column: span 4 !important; }
    .sg-kpi, .sg-chart, .sg-work, .sg-advisory { break-inside: avoid; }
}

/* Focus ring: gold on light, gold on dark (both clear 3:1 non-text contrast). */
.rz-button:focus-visible,
.rz-textbox:focus-visible,
.rz-dropdown:focus-visible,
.rz-navigation-item-link:focus-visible {
    outline: 2px solid var(--signet-gold);
    outline-offset: 2px;
}

/* Branded progress: maroon → gold, the tile's own sweep. */
.rz-progressbar-value,
.rz-progressbar-indeterminate-value {
    background-color: var(--sg-primary) !important;
    background-image: linear-gradient(90deg, var(--signet-primary), var(--signet-gold)) !important;
}

.rz-progressbar-circular .rz-progressbar-circular-fill {
    stroke: var(--sg-primary) !important;
}

/* ---------- Verdict chips (module 10) ----------
   One class per verdict; text is the verdict word, never colour alone. */
.sg-verdict {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.375rem 0.875rem;
    border-radius: 999px;
    font-weight: 700;
    letter-spacing: 0.3px;
    text-transform: uppercase;
    font-size: 0.8125rem;
    border: 1px solid currentColor;
}

.sg-verdict--valid   { color: var(--sg-verdict-valid);   background: var(--sg-verdict-valid-bg); }
.sg-verdict--invalid { color: var(--sg-verdict-invalid); background: var(--sg-verdict-invalid-bg); }
.sg-verdict--hold    { color: var(--sg-verdict-hold);    background: var(--sg-verdict-hold-bg); }

/* ---------- Form validation (kit classes) ---------- */
.valid.modified:not([type=checkbox]) { outline: 1px solid var(--sg-success); }
.invalid { outline: 1px solid var(--sg-danger); }
.validation-message { color: var(--sg-danger); }

/* ---------- Boot splash (index.html) ---------- */
.loading-container {
    gap: 1rem;
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 9999;
    background: transparent;
    user-select: none;
}

.loading-logo {
    width: 96px;
    height: 96px;
    position: relative;
    animation: sg-pulse 1.5s ease-in-out infinite;
}

.loading-logo-image {
    width: 100%;
    height: 100%;
    display: block;
    border-radius: 50%;
}

/* Ring: maroon track, gold sweep — the seal being pressed. */
.loading-logo::before {
    content: '';
    position: absolute;
    inset: -14px;
    border-radius: 50%;
    border: 3px solid rgba(142, 14, 14, 0.15);
    border-top-color: var(--signet-gold);
    animation: sg-spin 1s linear infinite;
    pointer-events: none;
}

[data-theme="dark"] .loading-logo::before {
    border-color: rgba(249, 168, 37, 0.18);
    border-top-color: var(--signet-gold);
}

.loading-text {
    color: var(--sg-text-secondary);
    font-size: 0.9375rem;
    animation: sg-fade 1.5s ease-in-out infinite;
}

@keyframes sg-spin  { to { transform: rotate(360deg); } }
@keyframes sg-pulse { 0%, 100% { transform: scale(0.96); } 50% { transform: scale(1.04); } }
@keyframes sg-fade  { 0%, 100% { opacity: 0.45; } 50% { opacity: 1; } }

/* ---------- Auth shell (Layout/LoginLayout.razor) ----------
   The kit's DESIGN §8.1 two-panel card in HarmonyPx's class form (.px-auth → .sg-auth) on Signet tokens:
   brand panel on the header gradient (deep → crimson, never gold behind text), form panel on the semantic
   surface so it flips in dark mode, a faint brand wash behind the card. Collapses below 900px. */
.sg-auth {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: 2rem 1.25rem;
    background:
        radial-gradient(circle at 22% 18%, color-mix(in srgb, var(--signet-crimson) 10%, transparent), transparent 55%),
        radial-gradient(circle at 82% 88%, color-mix(in srgb, var(--signet-gold) 12%, transparent), transparent 52%),
        var(--sg-bg);
}

.sg-auth__shell {
    display: grid;
    grid-template-columns: 1.05fr .95fr;
    width: 100%;
    max-width: 60rem;
    min-height: 33rem;
    background: var(--sg-surface);
    border-radius: 2.75rem;
    overflow: hidden;
    box-shadow: 0 24px 60px rgba(43, 37, 35, .12), 0 4px 14px rgba(43, 37, 35, .08);
}

/* Grid items default to min-width:auto; without this the 21rem form pushes the collapsed card past a phone's edge. */
.sg-auth__shell > * {
    min-width: 0;
}

.sg-auth__brand {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 3.25rem 3rem;
    color: var(--signet-on-brand);
    background: var(--sg-header-gradient);
    overflow: hidden;
}

.sg-auth__brand::before {
    content: "";
    position: absolute;
    inset: 0;
    background:
        radial-gradient(circle at 85% 12%, color-mix(in srgb, var(--signet-on-brand) 12%, transparent), transparent 42%),
        radial-gradient(circle at 8% 92%, color-mix(in srgb, var(--signet-on-brand) 8%, transparent), transparent 38%);
}

.sg-auth__brand-content {
    position: relative;
    z-index: 1;
    max-width: 26rem;
}

.sg-auth__logo {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1rem;
    margin-bottom: 2rem;
}

.sg-auth__logo-mark img {
    width: 96px;
    height: 96px;
    display: block;
    border-radius: 20px;
    box-shadow: 0 8px 24px rgba(43, 37, 35, .12);
}

.sg-auth__logo-text {
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: .01em;
}

.sg-auth__headline {
    font-size: 2.1rem;
    line-height: 1.18;
    font-weight: 700;
    margin: 0 0 1rem;
    text-wrap: balance;
}

.sg-auth__tagline {
    font-size: 1rem;
    line-height: 1.6;
    opacity: .85;
    margin: 0 0 1.9rem;
}

.sg-auth__features {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: .65rem;
}

.sg-auth__features li {
    position: relative;
    padding-left: 1.7rem;
    opacity: .92;
    font-size: .95rem;
}

/* The check is the seal's own gold, used as an accent glyph on maroon, never as a text background. */
.sg-auth__features li::before {
    content: "\2713";
    position: absolute;
    left: 0;
    font-weight: 700;
    color: var(--signet-gold);
}

.sg-auth__brand-footer {
    position: relative;
    z-index: 1;
    margin-top: 2rem;
    font-size: .8rem;
    opacity: .7;
}

.sg-auth__panel {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 3rem 2.75rem;
    background: var(--sg-surface);
    color: var(--sg-text);
}

.sg-auth__form {
    width: 100%;
    max-width: 21rem;
}

.sg-auth__mobile-brand {
    display: none;
    align-items: center;
    gap: .625rem;
    margin-bottom: 1.5rem;
    font-weight: 600;
    color: var(--sg-text);
}

.sg-auth__mobile-brand img {
    width: 28px;
    height: 28px;
    border-radius: 6px;
    display: block;
}

.sg-auth__head {
    margin-bottom: 1.75rem;
}

.sg-auth__title {
    font-weight: 700;
    margin: 0;
    color: var(--sg-primary);
}

.sg-auth__subtitle {
    color: var(--sg-text-secondary);
    margin-top: .35rem;
}

.sg-auth__form .rz-form-field,
.sg-auth__form .rz-textbox,
.sg-auth__form .rz-password {
    width: 100%;
}

.sg-auth__form .rz-button.sg-auth__submit,
.sg-auth__form .rz-button.sg-auth__choice {
    width: 100%;
}

.sg-auth__form .rz-button.sg-auth__choice {
    justify-content: flex-start;
}

/* Dark mode: a quieter wash and a deeper shadow; the brand panel keeps its own dark gradient token. */
[data-theme="dark"] .sg-auth {
    background:
        radial-gradient(circle at 22% 18%, color-mix(in srgb, var(--signet-crimson) 16%, transparent), transparent 55%),
        radial-gradient(circle at 82% 88%, color-mix(in srgb, var(--signet-gold) 8%, transparent), transparent 52%),
        var(--sg-bg);
}

[data-theme="dark"] .sg-auth__shell {
    box-shadow: 0 24px 60px rgba(0, 0, 0, .45), 0 4px 14px rgba(0, 0, 0, .30);
}

.sg-auth__theme-toggle {
    position: fixed;
    top: 1rem;
    right: 1rem;
    z-index: 1100;
    color: var(--sg-text-secondary);
}

@media (max-width: 900px) {
    .sg-auth {
        padding: 1.25rem;
    }

    .sg-auth__shell {
        grid-template-columns: 1fr;
        max-width: 26rem;
        min-height: 0;
        border-radius: 2rem;
    }

    .sg-auth__brand {
        display: none;
    }

    .sg-auth__panel {
        padding: 2.5rem 2rem;
    }

    .sg-auth__mobile-brand {
        display: flex;
    }
}

/* A page summary is muted body text, not a brand colour. Radzen's .rz-color-secondary means the
   secondary BRAND hue, which rendered the summary line red in light and teal in dark. */
.sg-page-summary { color: var(--sg-text-secondary); }

/* ---------- Standard page kit (SIGNET_DESIGN.md §8-§9) ----------
   Tokens only. The kit must not introduce a colour: the grid, the card and the change log all
   inherit the Radzen theme bridged to --sg-* in the sections above. */
.sg-loader { padding: 2rem 1rem; }
.sg-loader__text { color: var(--sg-text-secondary); }

.sg-changelog { background: var(--sg-surface-2); border-color: var(--sg-border); }

/* The column picker and the paging summary are new surfaces; keep them on the semantic tokens so
   they read correctly in dark mode rather than inheriting a Radzen light default. */
.rz-datatable .rz-paging-summary { color: var(--sg-text-secondary); }

/* ---------- Radzen adjustments carried from HarmonyHR ---------- */
.rz-notification {
    inset-block-start: 1rem !important;
    inset-inline-end: 1rem !important;
}

.rz-dialog { border-radius: 0.5rem; }
.rz-dialog-wrapper .rz-dialog {
    box-shadow: 0 4px 12px rgba(43, 37, 35, 0.08), 0 1px 2px rgba(43, 37, 35, 0.06);
}

#blazor-error-ui {
    color-scheme: light only;
    background: #fff8e1;
    border-top: 3px solid var(--signet-gold);
    color: #2b2523;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

/* ---- Hierarchical register node (ReferenceCodesView tree; SIGNET_DESIGN.md §8) -------------
   The row inside a RadzenTree node: actions, then the code, then the description, then any
   status badge, with delete pushed to the far right so it is never adjacent to edit.
   Signet tokens only — HarmonyHR's --hr-* never cross the boundary (CLAUDE.md rule 16). */
.sg-tree-node {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    width: 100%;
    min-width: 0;
    padding: 0.15rem 0;
}

.sg-tree-code {
    font-family: var(--rz-text-font-family-monospace, monospace);
    font-size: 0.82rem;
    color: var(--sg-text-secondary);
    padding: 0.05rem 0.4rem;
    border: 1px solid var(--sg-border, rgba(0, 0, 0, .12));
    border-radius: 0.25rem;
    white-space: nowrap;
    margin-left: 0.25rem;
}

.sg-tree-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The city on a tree node: secondary to the name it follows, never competing with it. Muted and
   smaller, so a node still reads code -> name; the flex gap is the only separator it needs. */
.sg-tree-city {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.82rem;
    color: var(--sg-text-secondary);
}

.sg-tree-delete { margin-left: auto; }

/* Radzen sizes .rz-treenode-label to its content, so a node's own width:100% resolves to the width of
   its text and `margin-left:auto` on delete has nothing to push against. Let the label fill the row. */
.rz-treenode-label:has(.sg-tree-node) { flex: 1 1 auto; min-width: 0; }

/* The rule above a transaction document's footer verbs (SgDocumentActions, rationale C36). */
.sg-doc-actions-rule { border: 0; border-top: 1px solid var(--sg-border); margin: 0; }

/* ---- Signature image (Signatories; rationale C46) -----------------------------------------
   The stored image in a bordered frame, the empty drop target that opens the file picker, and the
   file input itself hidden without display:none so the label still reaches it. */
.sg-signature-frame {
    display: inline-block;
    border: 1px solid var(--sg-border, rgba(0, 0, 0, .12));
    border-radius: 0.25rem;
    padding: 0.5rem;
    background: var(--sg-surface, #fff);
}
.sg-signature-frame img { max-height: 80px; max-width: 300px; display: block; }
.sg-signature-drop {
    border: 2px dashed var(--sg-border, rgba(0, 0, 0, .2));
    border-radius: 0.5rem;
    padding: 1rem;
    text-align: center;
    color: var(--sg-text-secondary);
}
.sg-visually-hidden {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ---- The expanded row of a grid wider than its card (rationale C50) -----------------------
   A master-detail or transaction page opens the record's Info tab INSIDE the grid, in a <tr> whose
   single <td> spans every column - so the detail is as wide as the TABLE, not as wide as the card.
   On a grid that scrolls sideways (Registration declares 1,972px against the 890px the card has at
   1,280 with the menu open) that put half of the document off the right-hand edge of the page whose
   whole job is to show it: a registered bond's Registration state, Category version, Line, Obligee,
   Effective and Issued were all present, all correct, and all unreachable without dragging the grid
   sideways. Nothing could see it but a screenshot - the fields are in the DOM at their full size, and
   the zero-width lint measures COLUMNS.

   The cell's width cannot be overridden (a table-cell takes its width from the colspan), so the
   TEMPLATE inside it is what is constrained. `position: sticky; left: 0` then keeps the document in
   view while the columns above it scroll. The width is the viewport less the sidebar and the card's
   own margins, floored by the cell so a narrow grid is unaffected. */
.rz-data-grid-data { position: relative; }
.rz-expanded-row-template {
    position: sticky;
    left: 0;
    box-sizing: border-box;
    width: min(100%, calc(100vw - 420px));
}

/* A caption wraps (18 Sep 2026, tranche-1 visual pass, rationale C70). Radzen's theme sets `white-space: nowrap` on
   `.rz-text-caption`, which is fine for the two-word labels the kit writes and wrong the moment a caption carries DATA:
   the category field panel captions each field with its NAME (up to 200 characters, authored on the Category page since
   C65), and one long name pushed the instrument's whole Info tab 221px past the window at 1366x633 - every value below it
   wrapped correctly, the label did not, and nothing but the dialog-fit sweep's long-value pass saw it. Captions never
   need a single line; a label that wraps is read, a label that runs off the screen is not. */
.rz-text-caption { white-space: normal; overflow-wrap: anywhere; }


/* ---- Validate: the gate panel and the composed answer (plan WP11, rationale C71) -----------------
   The Validate page is not a CRUD list: above its register sits the thing an officer actually does -
   a serial, a port, the category's own fields, and the answer. These rules give that block a frame
   inside the page's card without nesting a second card, and keep every label WRAPPING rather than
   clipping (the caption rule above, paid for once already in C70).

   The facts and the four checks are laid out as flex items with a MINIMUM width and no fixed one, so
   a long issuer name grows its own box and pushes the next one to the following line instead of
   running off the right-hand edge - which is what the width lessons of C29, C49 and C70 are all
   about. Nothing here names a colour: the badges carry the semantic tokens, and a verdict is never
   the brand maroon or gold (SIGNET_DESIGN.md). */
.sg-validate-panel {
    border: 1px solid var(--sg-border, rgba(0, 0, 0, 0.12));
    border-radius: var(--rz-border-radius, 4px);
    padding: 1rem;
    margin-bottom: 1rem;
}

.sg-validation-answer {
    border-top: 1px solid var(--sg-border, rgba(0, 0, 0, 0.12));
    padding-top: 0.75rem;
}

.sg-validation-fact,
.sg-validation-check {
    flex: 1 1 10rem;
    min-width: 10rem;
    max-width: 22rem;
    overflow-wrap: anywhere;
}

/* The field-match table is EVIDENCE, not a register: a plain table, so it brings no pager, no scroller
   and no width budget of its own to four rows of text inside a panel that is already inside a card.
   Every cell wraps; a container number that is longer than its column grows its row. */
.sg-field-matches { width: 100%; border-collapse: collapse; }
.sg-field-matches th,
.sg-field-matches td {
    text-align: left;
    padding: 0.25rem 0.75rem 0.25rem 0;
    border-bottom: 1px solid var(--sg-border, rgba(0, 0, 0, 0.08));
    overflow-wrap: anywhere;
    font-size: 0.875rem;
}
.sg-field-matches th { font-weight: 600; }

/* A badge never forces a dialog to scroll sideways (18 Sep 2026, C54 sweep). Radzen's badge is
   white-space: nowrap, so an unexpectedly long word in one - a check result the page has not been taught -
   grew to 1,791px inside a 1,100px dialog. It wraps now, and the value is still legible. */
.sg-validation-check .rz-badge,
.sg-validate-panel .rz-badge {
    white-space: normal;
    overflow-wrap: anywhere;
    max-width: 100%;
}

/* Category Authoring's expanded row (CTPL plan WP-M5, story CT8): nine tabs since Cross-references joined them. At Radzen's
   1rem a side the strip ran past the card at 1366x633 and the last tab, Policy, was cut to "PO" - seen in a photograph, as
   C65's seventh tab was. .6rem a side keeps every label whole and the strip inside the card. */
.sg-category-tabs { --rz-tabs-tab-padding-inline: .6rem; }
/* Narrower than the 1366px gate (the registration smoke runs at 1280) the strip WRAPS to a second row rather than clip
   Policy behind the card's edge: a tab nobody can see is a tab nobody can open. */
.sg-category-tabs .rz-tabview-nav { flex-wrap: wrap; }

/* ---------- Contextual help (Components/SgHelpDrawer, SgHelpFieldsButton, SgHelpTip; js/help.js) ----------
   docs/CONTEXTUAL_HELP_IMPLEMENTATION_PLAN.md rulings 9 and 10. The drawer is global because it pushes the page body,
   sits above the Radzen dialog layer (non-modal: the user keeps working in the dialog) and pulses inputs outside the
   component. Every colour here is a --sg-* or --rz-* token; a tint is a color-mix() of one. No literal colour.
   help.js sets --sg-help-top (the header's bottom) and --sg-help-width (320 .. viewport - 200, default 400). */
:root {
    --sg-help-width: 400px;
    --sg-help-top: 56px;
    --sg-help-accent: var(--sg-primary);
    --sg-help-accent-soft: color-mix(in srgb, var(--sg-primary) 12%, transparent);
    --sg-help-accent-strong: color-mix(in srgb, var(--sg-primary) 24%, transparent);
    --sg-help-muted: var(--sg-text-secondary);
    --sg-help-border: var(--sg-border);
}

.sg-help-drawer {
    position: fixed;
    top: var(--sg-help-top);
    right: 0;
    bottom: 0;
    width: var(--sg-help-width);
    max-width: 100vw;
    z-index: calc(var(--rz-dialog-zindex, 1001) + 4);   /* above the dialog wrapper and mask: usable while a dialog is open */
    background: var(--sg-surface);
    color: var(--sg-text);
    border-left: 1px solid var(--sg-help-border);
    box-shadow: -6px 0 20px color-mix(in srgb, var(--sg-text) 14%, transparent);
    display: flex;
    flex-direction: column;
    font-size: 0.875rem;
}
.sg-help-drawer__resize { position: absolute; left: -4px; top: 0; bottom: 0; width: 8px; cursor: ew-resize; }
.sg-help-drawer__head { display: flex; align-items: center; gap: 0.5rem; padding: 0.6rem 0.75rem 0.4rem 1rem; border-bottom: 1px solid var(--sg-help-border); }
.sg-help-drawer__icon { color: var(--sg-help-accent); }
.sg-help-drawer__title { flex: 1; min-width: 0; font-weight: 600; font-size: 1rem; color: var(--sg-help-accent); overflow-wrap: anywhere; }
.sg-help-drawer__kind { font-size: 0.7rem; font-weight: 400; color: var(--sg-help-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.sg-help-drawer__body { flex: 1; min-height: 0; overflow: auto; }
.sg-help-drawer__body .rz-tabview-panels { padding: 0.75rem 1rem 1.25rem; }
.sg-help-drawer h4 { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--sg-help-muted); margin: 1rem 0 0.4rem; }
.sg-help-drawer h4:first-child { margin-top: 0; }
.sg-help-drawer p { margin: 0 0 0.5rem; line-height: 1.45; }
.sg-help-drawer ul { margin: 0 0 0.5rem; padding-left: 1.1rem; }
.sg-help-drawer li { margin-bottom: 0.2rem; line-height: 1.4; }
.sg-help-drawer a { color: var(--sg-help-accent); }
.sg-help-muted { color: var(--sg-help-muted); }
.sg-help-footer { margin-top: 1rem; font-size: 0.72rem; color: var(--sg-help-muted); }
.sg-help-orgnote { border-left: 3px solid var(--sg-warning); background: var(--sg-surface-2); padding: 0.5rem 0.75rem; border-radius: 4px; }

/* The verbs on this page: on = the session holds it, off = it does not. */
.sg-help-roles { display: flex; flex-direction: column; gap: 0.35rem; }
.sg-help-role { display: flex; gap: 0.5rem; align-items: baseline; }
.sg-help-badge { display: inline-block; flex: none; font-size: 0.7rem; font-weight: 600; padding: 0.1rem 0.45rem; border-radius: 999px; white-space: nowrap; }
.sg-help-badge--on { background: var(--sg-success); color: var(--sg-on-primary); }
.sg-help-badge--off { background: var(--sg-surface-2); color: var(--sg-help-muted); border: 1px solid var(--sg-help-border); }
.sg-help-role--off .sg-help-role__text { color: var(--sg-help-muted); }

/* The flow strip: upstream -> this page -> downstream. */
.sg-help-flow { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr); gap: 0.35rem; align-items: center; margin-bottom: 0.5rem; }
.sg-help-flow__col { display: flex; flex-direction: column; gap: 0.25rem; }
.sg-help-flow__node { border: 1px solid var(--sg-help-border); border-radius: 6px; padding: 0.2rem 0.4rem; font-size: 0.75rem; line-height: 1.25; background: var(--sg-surface-2); overflow-wrap: anywhere; }
.sg-help-flow__node a { text-decoration: none; }
.sg-help-flow__node a:hover { text-decoration: underline; }
.sg-help-flow__self { border: 2px solid var(--sg-help-accent); background: var(--sg-help-accent-soft); border-radius: 6px; padding: 0.4rem; font-weight: 600; text-align: center; font-size: 0.78rem; overflow-wrap: anywhere; }
.sg-help-flow__arrow, .sg-help-arrow-svg { color: var(--sg-help-accent); }
.sg-help-arrow-svg { display: block; }

/* The status stepper; the selected record's status is the filled step. */
.sg-help-stepper { display: flex; flex-wrap: wrap; align-items: center; gap: 0.15rem 0; margin: 0.25rem 0 0.5rem; }
.sg-help-step { border: 1px solid var(--sg-help-accent-strong); background: var(--sg-help-accent-soft); border-radius: 999px; padding: 0.25rem 0.6rem; font-size: 0.75rem; font-weight: 600; white-space: nowrap; cursor: default; }
.sg-help-step--current { background: var(--sg-primary); color: var(--sg-on-primary); border-color: var(--sg-primary); box-shadow: 0 0 0 3px var(--sg-help-accent-strong); }
.sg-help-step--terminal { border-style: dashed; }
.sg-help-arrow { display: inline-flex; flex-direction: column; align-items: center; padding: 0 0.15rem; min-width: 3.2rem; cursor: help; color: var(--sg-help-accent); }
.sg-help-arrow__label { font-size: 0.62rem; color: var(--sg-help-accent); font-weight: 600; text-align: center; line-height: 1.1; }
.sg-help-gap { width: 1rem; }
.sg-help-transitions { width: 100%; border-collapse: collapse; font-size: 0.78rem; }
.sg-help-transitions td { border-top: 1px solid var(--sg-help-border); padding: 0.35rem 0.25rem; vertical-align: top; }
.sg-help-transitions td:first-child { white-space: nowrap; font-weight: 600; }

/* The Fields tab. */
.sg-help-fieldsearch { flex: 1; min-width: 10rem; }
.sg-help-fields { width: 100%; border-collapse: collapse; font-size: 0.78rem; }
.sg-help-fields th { text-align: left; font-size: 0.7rem; color: var(--sg-help-muted); text-transform: uppercase; padding: 0.25rem; border-bottom: 1px solid var(--sg-help-border); }
.sg-help-fields td { padding: 0.35rem 0.25rem; vertical-align: top; overflow-wrap: anywhere; }
.sg-help-fields tr.sg-help-field { cursor: pointer; }
.sg-help-fields tr.sg-help-field td { border-top: 1px solid var(--sg-help-border); }
.sg-help-fields tr.sg-help-field__rules td { padding-top: 0; cursor: pointer; }
.sg-help-fields tr.sg-help-field:hover td, .sg-help-fields tr.sg-help-field:hover + tr.sg-help-field__rules td { background: var(--sg-hover); }
.sg-help-fields tr.sg-help-field--active td, .sg-help-fields tr.sg-help-field--active + tr.sg-help-field__rules td { background: var(--sg-help-accent-soft); }
.sg-help-fields td.sg-help-field__name { font-weight: 600; width: 26%; }
.sg-help-fields .sg-help-field__section { font-weight: 400; }
.sg-help-fields .sg-help-validation { color: color-mix(in srgb, var(--sg-warning) 55%, var(--sg-text)); margin: 0; padding-left: 1rem; }
.sg-help-section-chip { display: inline-flex; gap: 0.25rem; align-items: center; background: var(--sg-help-accent-soft); color: var(--sg-help-accent); border-radius: 999px; padding: 0.1rem 0.5rem; font-size: 0.72rem; font-weight: 600; }
.sg-help-section-chip button { border: 0; background: none; color: inherit; cursor: pointer; padding: 0; font-size: 0.9rem; line-height: 1; }

/* Dependencies & effects. */
.sg-help-effects { width: 100%; border-collapse: collapse; font-size: 0.78rem; }
.sg-help-effects td { border-top: 1px solid var(--sg-help-border); padding: 0.3rem 0.25rem; vertical-align: top; }
.sg-help-effects td:first-child { width: 7rem; }
.sg-help-effects tr.sg-help-effects__action td { background: var(--sg-surface-2); font-weight: 600; border-top: 2px solid var(--sg-help-border); }

/* The field highlight (help.js highlightField): a 2-second pulse in the primary. */
@keyframes sgHelpPulse {
    0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--sg-primary) 75%, transparent); }
    50% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--sg-primary) 25%, transparent); }
    100% { box-shadow: 0 0 0 0 transparent; }
}
.sg-help-pulse { animation: sgHelpPulse 0.7s ease-out 3; outline: 2px solid var(--sg-help-accent) !important; outline-offset: 2px; border-radius: 4px; }

/* Wide screens: the page body makes room for the drawer, and an open dialog is pushed aside only when help.js found that
   the widest one fits beside it (sg-help-push-dialogs); otherwise the drawer overlays the dialog (ruling 10). */
@media (min-width: 992px) {
    body.sg-help-open .rz-body { margin-right: var(--sg-help-width); }
    body.sg-help-open.sg-help-push-dialogs .rz-dialog-wrapper { padding-right: var(--sg-help-width); }
    /* The expanded row's template (C49's rule above) is the viewport less the sidebar and the card's margins; with the page
       pushed it is the drawer's width less again, or a master-detail row runs past its card - seen on Category Authoring
       (story CH6): the tab strip cut at "OFFLIN" and the field grid clipped. Narrowed, the strip wraps as it does at 1280. */
    body.sg-help-open .rz-expanded-row-template { width: min(100%, calc(100vw - 420px - var(--sg-help-width))); }
}

/* Phone width: a full-width overlay. */
@media (max-width: 767px) {
    .sg-help-drawer { width: 100vw; left: 0; border-left: 0; }
    .sg-help-drawer__resize { display: none; }
    .sg-help-flow { grid-template-columns: 1fr; }
    .sg-help-flow__arrow { transform: rotate(90deg); justify-self: center; }
}

/* Four tabs in 400 px: compact labels so "Dependencies & effects" fits beside the other three. */
.sg-help-drawer { --rz-tabs-tab-padding-inline: 0.5rem; }
.sg-help-drawer .rz-tabview-nav { flex-wrap: nowrap; }
.sg-help-drawer .rz-tabview-nav li > button,
.sg-help-drawer .rz-tabview-nav li > a { padding-inline: 0.45rem; font-size: 0.72rem; white-space: nowrap; }
/* Radzen's tab title is uppercase with Material letter-spacing: at 400 px it pushed "Dependencies & effects" 30 px past the
   drawer's edge (seen in the CH3 photograph). The spacing goes; the labels stay whole. */
.sg-help-drawer .rz-tabview-title { letter-spacing: 0; }
.sg-help-fields-btn .rz-button-icon-left { font-size: 1.1rem; }

/* The help search (above the tabs) and its results. */
.sg-help-search { position: relative; display: flex; align-items: center; padding: 0.5rem 0.75rem 0.5rem 1rem; border-bottom: 1px solid var(--sg-help-border); }
.sg-help-search__icon { position: absolute; left: 1.45rem; font-size: 1.1rem; color: var(--sg-help-muted); pointer-events: none; }
.sg-help-search__input { width: 100%; padding-left: 2rem !important; padding-right: 1.8rem !important; }
.sg-help-search__clear { position: absolute; right: 1.2rem; border: 0; background: none; font-size: 1.2rem; line-height: 1; cursor: pointer; color: var(--sg-help-muted); }
.sg-help-results { padding: 0.75rem 1rem 1.25rem; }
.sg-help-hit { display: flex; flex-direction: column; gap: 0.15rem; width: 100%; text-align: left; background: none; border: 1px solid var(--sg-help-border); border-radius: 6px; padding: 0.5rem 0.65rem; margin-bottom: 0.45rem; cursor: pointer; font: inherit; color: inherit; }
.sg-help-hit:hover, .sg-help-hit:focus-visible { border-color: var(--sg-help-accent); background: var(--sg-hover); outline: none; }
.sg-help-hit__title { font-weight: 600; }
.sg-help-hit__where { font-size: 0.75rem; color: var(--sg-help-accent); }
.sg-help-hit__snippet { font-size: 0.8rem; color: var(--sg-help-muted); }
.sg-help-guide { display: flex; align-items: center; gap: 0.35rem; margin-top: 0.5rem; font-size: 0.85rem; }
.sg-help-guide .rzi { font-size: 1.1rem; color: var(--sg-help-accent); }

/* The per-field tip (Components/SgHelpTip) beside a label. */
.sg-help-tip { display: inline-flex; align-items: center; vertical-align: middle; margin-left: 0.25rem; cursor: help; color: var(--sg-text-secondary); border-radius: 50%; }
.sg-help-tip .rzi { font-size: 16px; }
.sg-help-tip:hover, .sg-help-tip:focus-visible { color: var(--sg-help-accent); outline: none; }
/* A tip inside a form field's floating label (Radzen sets pointer-events: none on the label): the tip alone takes the
   pointer, so hovering it shows the description while a click elsewhere on the label still reaches the input. */
.rz-form-field-label .sg-help-tip { pointer-events: auto; }
/* SgHelpFieldsButton AsRow: a generated dialog's first row, the help button right-aligned. */
.sg-help-dialog-row { display: flex; justify-content: flex-end; margin: -0.5rem 0 -0.75rem; }
/* ---------- end contextual help ---------- */
