/* ── Self-hosted fonts — no Google Fonts, no CDN. A branch till runs whole days with no internet
   (FR-SYN-01), and a blocking request to an external font host would stall first paint until it
   timed out. All three families are OFL, Latin-subset, licences alongside the files in
   wwwroot/fonts. ShellColdLoadTests fails the build on any off-origin request.

   The "Kaunta" system uses three faces, each with one job (docs/design-plan.md):

   INSTRUMENT SANS carries the interface — every label, cell and sentence.
   BRICOLAGE GROTESQUE is the display voice: page titles and dashboard numerals, nothing else.
   JETBRAINS MONO sets part numbers, quantities and money. Those ARE the content of this product,
   and it has the unambiguous 0/O and 1/l/I a counter needs when a customer is holding the old
   part. Two static weights — 400 for cells, 600 for the specimen and the ticket total. */
@font-face {
    font-family: "Instrument Sans";
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url("fonts/instrument-sans-latin-wght-normal.woff2") format("woff2-variations");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: "Bricolage Grotesque";
    font-style: normal;
    font-weight: 200 800;
    font-display: swap;
    src: url("fonts/bricolage-grotesque-latin-wght-normal.woff2") format("woff2-variations");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("fonts/jetbrains-mono-latin-400-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("fonts/jetbrains-mono-latin-600-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── Design tokens — "Aurora" (layout: Kaunta) ─────────────────────────────────────────────────
   2026-09-26: the palette was replaced — see docs/design-plan.md. The layout (console + islands)
   is Kaunta's and unchanged. What is new is COLOUR WITH A JOB: every module owns a gradient
   (--r360-mod-*, keyed on data-r360-module), the CTA is the brand gradient rather than ink, and
   the canvas carries three soft glows. The house rule every gradient obeys: it is a
   background-IMAGE over a SOLID background-color, because the E2E contrast walker reads
   backgroundColor only — a gradient that was the sole colour of a surface would be judged as
   transparent.

   Kaunta's original notes follow.
   See docs/design-plan.md for the direction and docs/ui-conventions.md for usage.

   Colour tokens are defined in terms of the --mud-palette-* variables rather than literal hex.
   That is what makes light mode, dark mode and tenant branding all work from one definition:
   MudThemeProvider swaps the palette underneath and every token below follows, with no second
   implementation. [Aurora] The one exception is the module INK, which has a dark-mode block
   (:root[data-r360-theme="dark"]) — see the Aurora section near the end of this file.

   TWO ACTION COLOURS. --r360-primary is the ACCENT: selected, focused, a link, the place you are.
   --r360-cta is the call to action — [Aurora] the brand gradient on solid indigo, the same in both
   schemes; a filled primary BUTTON goes one step further and takes its page's module gradient.
   Status colours never act.

   The -text variants exist because a saturated status colour is a mid-tone, and a mid-tone has no
   safe pairing with black OR white at 12-13px. Fill is for dots, icons and 3:1 indicators; the
   moment a status colour lands on WORDS, the -text token is the only permitted one. */
:root {
    /* Type */
    --r360-font-ui: "Instrument Sans", "Segoe UI", "Helvetica Neue", Arial, sans-serif;
    --r360-font-display: "Bricolage Grotesque", "Instrument Sans", "Segoe UI", Arial, sans-serif;
    --r360-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Consolas, monospace;

    /* Ground */
    --r360-canvas: var(--mud-palette-background);
    --r360-canvas-inset: var(--mud-palette-background-gray);
    --r360-surface: var(--mud-palette-surface);
    --r360-surface-2: var(--mud-palette-table-hover);
    --r360-hairline: var(--mud-palette-lines-default);
    --r360-hairline-strong: var(--mud-palette-lines-inputs);
    --r360-ink: var(--mud-palette-text-primary);
    --r360-ink-muted: var(--mud-palette-text-secondary);
    --r360-ink-faint: var(--mud-palette-text-disabled);

    /* Accent — selection, focus, links, the active console item. Follows tenant branding. */
    --r360-primary: var(--mud-palette-primary);
    --r360-primary-hover: var(--mud-palette-primary-darken);
    --r360-on-primary: var(--mud-palette-primary-text);
    --r360-accent: var(--mud-palette-primary);
    --r360-accent-text: var(--mud-palette-primary-darken);
    --r360-accent-soft: color-mix(in srgb, var(--mud-palette-primary) 11%, var(--mud-palette-surface));
    --r360-ring: color-mix(in srgb, var(--mud-palette-primary) 30%, transparent);

    /* Call to action — [Aurora] the brand gradient on its solid indigo. Fixed rather than following
       the palette: white on #4F46E5 is 6.29:1, and it holds on the dark canvas too, so it is one
       colour in both schemes. The palette Dark slot still grounds MudBlazor TOOLTIPS. */
    --r360-cta: #4F46E5;
    --r360-cta-hover: #4338CA;
    --r360-on-cta: #FFFFFF;
    --r360-brand-gradient: linear-gradient(135deg, #4F46E5 0%, #7C3AED 52%, #DB2777 100%);
    --r360-brand-bright: linear-gradient(120deg, #6366F1 0%, #A855F7 50%, #EC4899 100%);

    /* Module identity — the START module's values; each [data-r360-module] block below overrides
       the five raw hues. -a/-b are the FILL pair and white text on either stop clears 4.5:1; -c/-d
       are the BRIGHT pair, decorative only (edges, glows, hover wells) and never under words;
       -ink is the text-safe hue on a surface. */
    --r360-mod-a: #4F46E5;
    --r360-mod-b: #7C3AED;
    --r360-mod-c: #6366F1;
    --r360-mod-d: #A855F7;
    --r360-mod-ink: #4338CA;

    /* Status. Fill for dots/icons, -text for words, -bg for tag grounds (solid, never rgba, so a
       tag reads the same over a hovered row as over a resting one). */
    --r360-confirmed: var(--mud-palette-success);
    --r360-confirmed-text: var(--mud-palette-success-darken);
    --r360-confirmed-bg: color-mix(in srgb, var(--mud-palette-success) 13%, var(--mud-palette-surface));
    --r360-attention: var(--mud-palette-warning);
    --r360-attention-text: var(--mud-palette-warning-darken);
    --r360-attention-bg: color-mix(in srgb, var(--mud-palette-warning) 15%, var(--mud-palette-surface));
    --r360-failure: var(--mud-palette-error);
    --r360-failure-text: var(--mud-palette-error-darken);
    --r360-failure-bg: color-mix(in srgb, var(--mud-palette-error) 11%, var(--mud-palette-surface));

    /* Space — 4px base, nothing between steps */
    --r360-space-1: 4px;
    --r360-space-2: 8px;
    --r360-space-3: 12px;
    --r360-space-4: 16px;
    --r360-space-5: 20px;
    --r360-space-6: 24px;
    --r360-space-7: 32px;
    --r360-space-8: 48px;

    /* Radius — soft. Control / panel / modal, plus the pill every tag and capsule uses. */
    --r360-radius-control: 10px;
    --r360-radius-panel: 16px;
    --r360-radius-modal: 20px;
    --r360-radius-pill: 999px;

    /* Elevation — tinted with the ink hue rather than pure black, so a floating surface reads as
       lit from above on a cool canvas. Dark needs no switch: shadows are close to invisible there
       and surfaces read by LIFT instead (the dark Surface sits above its Background). */
    --r360-shadow-1: 0 1px 2px rgba(49, 46, 129, 0.05), 0 2px 6px rgba(49, 46, 129, 0.06);
    --r360-shadow-2: 0 10px 24px -8px rgba(79, 70, 229, 0.24), 0 2px 4px rgba(49, 46, 129, 0.06);
    --r360-shadow-3: 0 18px 40px -12px rgba(49, 46, 129, 0.32), 0 2px 6px rgba(49, 46, 129, 0.08);

    /* Motion */
    --r360-speed-fast: 120ms;
    --r360-speed-base: 180ms;
    --r360-speed-slow: 260ms;
    --r360-ease: cubic-bezier(0.2, 0.8, 0.2, 1);

    /* Shell geometry — the console along the bottom edge and the islands along the top. */
    --r360-console-h: 60px;
    --r360-console-gap: 12px;
    --r360-topline-h: 48px;

    /* Density — comfortable. See the compact override below. */
    --r360-row-h: 48px;
    --r360-cell-pad-y: 12px;
    --r360-text-body: 0.875rem;
    --r360-field-h: 42px;

    /* The pegboard — a parts-shop wall. A background-IMAGE, so the E2E contrast walker (which reads
       backgroundColor only) still finds the opaque canvas colour beneath it. */
    --r360-peg: color-mix(in srgb, var(--mud-palette-text-primary) 10%, transparent);

    /* ── Compatibility aliases — kept alive because scoped stylesheets still name them. */
    --r360-shadow-sm: var(--r360-shadow-1);
    --r360-shadow-md: var(--r360-shadow-2);
    --r360-speed: var(--r360-speed-base);
}

/* [!] The canvas colour is stated HERE rather than left to the runtime style block of
   MudThemeProvider, and it is not belt-and-braces. The E2E contrast walker climbs ancestors for the
   first background with alpha > 0, STOPS BEFORE <html>, and falls back to white when it finds none.
   So a canvas that only reaches the document element would have every measured dark-mode heading
   judged against white and fail for a reason nothing on screen shows. */
body {
    background-color: var(--mud-palette-background);
    /* [Aurora] The glows sit to the RIGHT and BELOW, deliberately away from the top-left where every
       page title and its muted lead sit: muted text is 5.0:1 on the bare mist and a glow under it
       would eat the margin. */
    background-image:
        radial-gradient(48rem 34rem at 100% -8%, var(--r360-glow-1), transparent 62%),
        radial-gradient(44rem 32rem at 4% 108%, var(--r360-glow-2), transparent 62%),
        radial-gradient(40rem 30rem at 82% 104%, var(--r360-glow-3), transparent 60%);
    background-attachment: fixed;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

/* Density is a user setting, persisted per device. MainLayout writes the attribute to <html> so it
   also reaches popovers and menus, which render outside the layout subtree. */
:root[data-r360-density="compact"] {
    --r360-row-h: 36px;
    --r360-cell-pad-y: 8px;
    --r360-text-body: 0.8125rem;
    --r360-field-h: 36px;
}

/* [!] Compact did almost nothing until these rules existed — MEASURED: a worklist row was 44px
   comfortable and 43px compact. `height` is a FLOOR on a table cell, not a ceiling, and every
   worklist puts a button in its last column; shrinking the text without shrinking the control
   shrinks nothing. This deliberately takes row actions below the 44px touch target: comfortable is
   the touch-screen mode, compact is for a mouse on a back-office screen, and the two cannot both
   honour a 44px target and a 36px row. */
:root[data-r360-density="compact"] .mud-table-row td .mud-button-root,
:root[data-r360-density="compact"] .mud-simple-table tbody td .mud-button-root {
    min-height: 24px;
    height: 24px;
    padding-block: 0;
    line-height: 1.2;
}

:root[data-r360-density="compact"] .mud-table-row td,
:root[data-r360-density="compact"] .mud-simple-table tbody td {
    padding-top: 5px;
    padding-bottom: 5px;
}

/* ── Boot splash — static, unlocalised, no script needed to show it and one line to hide it. The
   primary removal is the pure-CSS :has() rule below; the r360HideSplash call in MainLayout is only
   a fallback. Literal colours, because no palette exists yet when this paints: the light canvas,
   so the first frame is the same ground the shell settles into. */
#r360-splash {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1.25rem;
    background-color: #EEF2F6;
    background-image: radial-gradient(circle at 1px 1px, rgba(15, 23, 42, 0.10) 1px, transparent 1.5px);
    background-size: 24px 24px;
}

#r360-splash svg {
    width: 3.5rem;
    height: 3.5rem;
    color: #0F172A;
}

#r360-splash .r360-splash-word {
    font-family: var(--r360-font-display);
    font-weight: 700;
    font-size: 1.125rem;
    letter-spacing: -0.02em;
    color: #0F172A;
}

#r360-splash .r360-splash-bar {
    width: 8rem;
    height: 3px;
    border-radius: 999px;
    background: #DCE3EB;
    overflow: hidden;
}

#r360-splash .r360-splash-bar::after {
    content: "";
    display: block;
    width: 40%;
    height: 100%;
    border-radius: 999px;
    background: #2A5BFF;
    animation: r360-splash-pulse 1.1s ease-in-out infinite;
}

@keyframes r360-splash-pulse {
    0% { transform: translateX(-100%); }
    100% { transform: translateX(350%); }
}

body:has(.mud-layout) #r360-splash,
body:has(.r360-auth) #r360-splash {
    display: none;
}

/* ══ THE SHELL — "Console + Islands" ═══════════════════════════════════════════════════════════
   There is no app bar and no sidebar. Navigation lives in a floating CONSOLE docked along the
   bottom edge — the tool tray of a counter — and the top of the screen carries three small
   floating ISLANDS with the canvas visible between them.

   [!] ONE DOM TREE. The console and the launcher sheet are the SAME link elements in two CSS
   states (.r360-console--open). MainLayoutTests counts markup, Playwright runs in strict mode, and
   E2E journeys click nav-* links directly without opening anything — so every link exists exactly
   once and is always clickable. Nothing here may duplicate a link to get a second layout.

   Both measured elements (app-title, .r360-connectivity__label) sit on OPAQUE capsules. No
   backdrop-filter, no translucent ground: the contrast walker reads backgroundColor without
   compositing, so a glass island would be measured as whatever happened to be behind it. */

.r360-topline {
    position: sticky;
    top: 0;
    z-index: 1100;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(12rem, 27.5rem) minmax(0, 1fr);
    align-items: center;
    gap: var(--r360-space-3);
    padding: var(--r360-space-3) var(--r360-space-5) 0;
    /* The strip itself is not a bar: clicks fall through the gaps to the page beneath. */
    pointer-events: none;
}

/* A fade, not a fill: content scrolling under the islands dissolves into the canvas instead of
   colliding with them. A pseudo-element, so it is nobody's ancestor. */
.r360-topline::before {
    content: "";
    position: absolute;
    inset: 0 0 -14px 0;
    z-index: -1;
    background: linear-gradient(to bottom, var(--r360-canvas) 55%, transparent);
    pointer-events: none;
}

/* A 1024x768 till cannot spare the height: there the islands scroll away with the page and the
   console is the only persistent chrome. */
@media (max-height: 820px) {
    .r360-topline {
        position: static;
    }

    .r360-topline::before {
        display: none;
    }
}

.r360-island {
    pointer-events: auto;
    display: inline-flex;
    align-items: center;
    gap: 2px;
    min-height: var(--r360-topline-h);
    padding: 0 6px;
    background-color: var(--r360-surface);
    border: 1px solid var(--r360-hairline);
    border-radius: var(--r360-radius-panel);
    box-shadow: var(--r360-shadow-1);
    min-width: 0;
}

.r360-island--brand {
    justify-self: start;
    gap: 10px;
    padding: 0 16px 0 10px;
    color: var(--r360-ink);
}

.r360-island--status {
    justify-self: end;
}

.r360-wordmark {
    font-family: var(--r360-font-display);
    font-size: 0.9375rem;
    font-weight: 700;
    letter-spacing: -0.015em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The Counter Bar — the command palette, surfaced as the thing in the middle of the screen. A
   button drawn as a field: one focusable, same testid, same accessible name as before. */
.mud-button-root.r360-counterbar {
    pointer-events: auto;
    justify-self: stretch;
    display: flex;
    justify-content: flex-start;
    gap: 10px;
    min-height: var(--r360-topline-h);
    padding: 0 10px 0 14px;
    background-color: var(--r360-surface);
    border: 1px solid var(--r360-hairline);
    border-radius: var(--r360-radius-panel);
    box-shadow: var(--r360-shadow-1);
    color: var(--r360-ink-muted);
    font-weight: 500;
}

.mud-button-root.r360-counterbar:hover {
    background-color: var(--r360-surface);
    border-color: var(--r360-hairline-strong);
    box-shadow: var(--r360-shadow-2);
}

.r360-counterbar .mud-button-label {
    justify-content: flex-start;
    gap: 10px;
    min-width: 0;
}

.r360-counterbar__text {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: start;
}

.r360-island .mud-icon-button {
    color: var(--r360-ink-muted);
    padding: 8px;
}

.r360-island .mud-icon-button:hover {
    color: var(--r360-ink);
    background-color: var(--r360-surface-2);
}

/* ── The header on a phone ─────────────────────────────────────────────────────────────────────
   Three islands do not fit 400px — squeezed, they overlapped. Below 760px the header becomes ONE
   floating capsule: the mark, search as an icon, and the status controls pushed to the far end.
   The islands inside it lose their own borders and shadows, so it reads as a single object. Same
   DOM, same Tab order; only the drawing changes. The wordmark is hidden here, which no test
   observes — every shell assertion runs at the 1280px Playwright default. */
@media (max-width: 760px) {
    .r360-topline {
        display: flex;
        align-items: center;
        gap: 2px;
        margin: var(--r360-space-3) var(--r360-space-3) 0;
        padding: 4px;
        pointer-events: auto;
        background-color: var(--r360-surface);
        border: 1px solid var(--r360-hairline);
        border-radius: 18px;
        box-shadow: var(--r360-shadow-2);
    }

    .r360-topline::before {
        display: none;
    }

    .r360-topline .r360-island,
    .r360-topline .mud-button-root.r360-counterbar {
        min-height: 40px;
        padding: 0 4px;
        background-color: transparent;
        border: 0;
        border-radius: 14px;
        box-shadow: none;
    }

    .r360-topline .mud-button-root.r360-counterbar {
        flex: 0 0 auto;
        min-width: 40px;
        padding: 0 10px;
    }

    .r360-topline .mud-button-root.r360-counterbar:hover {
        background-color: var(--r360-surface-2);
        box-shadow: none;
    }

    .r360-island--brand {
        padding-inline: 8px 4px;
    }

    .r360-island--status {
        margin-inline-start: auto;
    }

    .r360-counterbar__text,
    .r360-counterbar .r360-kbd {
        display: none;
    }

    /* [!] The wordmark is HIDDEN, not removed. `display: none` takes it out of the accessibility
       tree as well as off the screen, so a phone user with a screen reader lost the product's name
       entirely — and `app-title` is an element this product's own shell tests look for. Clipped
       instead: the mark carries the identity to the eye, the name still reaches a reader. */
    .r360-wordmark {
        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;
    }

    /* No branch is configured, or one is: either way the phone shows the code plate only. */
    .r360-topline .r360-branch-none {
        display: none;
    }
}

/* ── The console ─────────────────────────────────────────────────────────────────────────────── */

.r360-console {
    position: fixed;
    left: var(--r360-console-gap);
    right: var(--r360-console-gap);
    bottom: var(--r360-console-gap);
    z-index: 1200;
    width: fit-content;
    max-width: calc(100vw - 2 * var(--r360-console-gap));
    margin-inline: auto;
    display: flex;
    align-items: center;
    gap: 6px;
    height: var(--r360-console-h);
    padding: 0 8px;
    background-color: var(--r360-surface);
    border: 1px solid var(--r360-hairline);
    border-radius: 22px;
    box-shadow: var(--r360-shadow-3);
}

.r360-console__launcher.mud-icon-button {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    border-radius: 14px;
    background-color: var(--r360-cta);
    background-image: var(--r360-brand-gradient);
    color: var(--r360-on-cta);
    box-shadow: 0 8px 18px -8px rgba(124, 58, 237, 0.75);
    transition: transform var(--r360-speed-fast) var(--r360-ease), box-shadow var(--r360-speed-base) var(--r360-ease);
}

.r360-console__launcher.mud-icon-button:hover {
    background-color: var(--r360-cta-hover);
    transform: translateY(-1px) rotate(-4deg);
    box-shadow: 0 12px 24px -8px rgba(219, 39, 119, 0.7);
}

/* The link strip. It scrolls sideways when a role has more links than the width allows (a full
   administrator at 1024px). overflow-x:auto forces overflow-y to clip as well, which would cut the
   hover labels off above the console — so the strip is made TALL with padding and pulled back with
   a negative margin, and only its children take pointer events. */
.r360-console__nav {
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
    padding-top: 56px;
    margin-top: -56px;
    pointer-events: none;
}

/* When a role has more links than the width allows, the strip scrolls sideways and its two ends
   fade, so a clipped icon reads as "more this way" rather than as a rendering fault. scroll-driven
   state is not needed: the fade is 14px of the strip's own padding, empty when nothing overflows. */
.r360-console:not(.r360-console--open) .r360-console__nav {
    padding-inline: 14px;
    margin-inline: -8px;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 14px, #000 calc(100% - 14px), transparent);
    mask-image: linear-gradient(to right, transparent, #000 14px, #000 calc(100% - 14px), transparent);
}

.r360-console__nav::-webkit-scrollbar {
    display: none;
}

.r360-console__nav .mud-navmenu {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 2px;
    margin: 0;
    padding: 0;
    pointer-events: auto;
}

/* [!] MudBlazor states .mud-nav-item as width:100% — right for a drawer, and in a row it made every
   item 205px wide inside a section sized for 42px, so the icons drew on top of one another.
   Measured in the browser, not inferred. */
.r360-console .mud-navmenu .mud-nav-item {
    flex: 0 0 auto;
    width: auto;
    position: relative;
}

.r360-console .r360-nav-section {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 2px;
    margin: 0 0 0 6px;
    padding: 0 0 0 8px;
    border-inline-start: 1px solid var(--r360-hairline);
}

.r360-console:not(.r360-console--open) .r360-nav-section:first-child {
    margin-inline-start: 0;
    padding-inline-start: 0;
    border-inline-start: 0;
}

/* Section headings are for the launcher sheet. In the console they stay in the DOM (they are the
   group names a screen reader announces) but are not drawn. */
.r360-console:not(.r360-console--open) .r360-nav-section__label,
.r360-console:not(.r360-console--open) .r360-console__group-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* [!] The specificity here is deliberate. The MudBlazor stylesheet states the active link as
   `.mud-navmenu.mud-navmenu-default .mud-nav-link.active:not(.mud-nav-link-disabled)` — (0,5,0) —
   and these have to beat it without !important, so each carries the console prefix as well. */
.r360-console .mud-navmenu.mud-navmenu-default .mud-nav-link {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 42px;
    height: 42px;
    min-height: 0;
    margin: 0;
    padding: 0;
    border-radius: 14px;
    color: var(--r360-ink-muted);
    font-size: 0.8125rem;
    font-weight: 600;
    white-space: nowrap;
    transition: background-color var(--r360-speed-fast) var(--r360-ease), color var(--r360-speed-fast) var(--r360-ease), width var(--r360-speed-base) var(--r360-ease);
}

.r360-console .mud-navmenu.mud-navmenu-default .mud-nav-link .mud-nav-link-icon {
    margin: 0;
    color: inherit;
    font-size: 1.375rem;
}

/* [Aurora] Hover tints the icon in its MODULE's hue — every console section carries
   data-r360-module, so the Sell icons warm up and the Stock icons turn teal. */
.r360-console .mud-navmenu.mud-navmenu-default .mud-nav-link:hover:not(.mud-nav-link-disabled) {
    background-color: var(--r360-mod-soft);
    color: var(--r360-mod-ink);
}

/* [!] The hover label below NEVER SHOWED, and the cause was MudBlazor's own: .mud-ripple sets
   overflow:hidden on every nav link so the ripple stays inside it, which clipped a label drawn
   above the link to nothing. Measured on the deployed site — opacity 1, positioned correctly,
   invisible. The link now lets its label out, and the ripple (the only thing that needed the
   clip, and an effect a till can do without) is switched off in the console. */
.r360-console .mud-navmenu.mud-navmenu-default .mud-nav-link.mud-ripple {
    overflow: visible;
}

.r360-console .mud-nav-link.mud-ripple::after {
    display: none;
}

/* The label of a resting link: not drawn, still the accessible name. On hover or keyboard focus
   it becomes a tooltip above the icon in the module's gradient — the same text node, so nothing
   is duplicated and the singleton-markup rule of MainLayoutTests holds. */
.r360-console:not(.r360-console--open) .mud-nav-link:not(.active) .mud-nav-link-text {
    position: absolute;
    left: 50%;
    bottom: calc(100% + 14px);
    z-index: 2;
    width: auto;
    margin: 0;
    padding: 6px 11px;
    border-radius: 10px;
    background-color: var(--r360-mod-a);
    background-image: var(--r360-mod-fill);
    color: #FFFFFF;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: 0.01em;
    white-space: nowrap;
    box-shadow: 0 10px 22px -8px var(--r360-mod-glow);
    opacity: 0;
    transform: translate(-50%, 6px) scale(0.96);
    transform-origin: 50% 100%;
    pointer-events: none;
    transition: opacity var(--r360-speed-fast) var(--r360-ease), transform var(--r360-speed-base) var(--r360-ease);
}

/* The pointer — a small diamond in the gradient's own colour, tucked under the bubble. */
.r360-console:not(.r360-console--open) .mud-nav-link:not(.active) .mud-nav-link-text::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: -4px;
    width: 9px;
    height: 9px;
    margin-left: -4.5px;
    border-radius: 2px;
    background-color: color-mix(in srgb, var(--r360-mod-a) 50%, var(--r360-mod-b));
    transform: rotate(45deg);
}

.r360-console:not(.r360-console--open) .mud-nav-link:not(.active):hover .mud-nav-link-text,
.r360-console:not(.r360-console--open) .mud-nav-link:not(.active):focus-visible .mud-nav-link-text {
    opacity: 1;
    transform: translate(-50%, 0) scale(1);
    transition-delay: 60ms;
}

/* The place you are: the active link opens out into a pill in its module's gradient. */
.r360-console .mud-navmenu.mud-navmenu-default .mud-nav-link.active:not(.mud-nav-link-disabled) {
    width: auto;
    padding: 0 14px 0 11px;
    background-color: var(--r360-mod-a);
    background-image: var(--r360-mod-fill);
    color: #FFFFFF;
    font-weight: 600;
    box-shadow: 0 8px 18px -8px var(--r360-mod-glow);
}

.r360-console .mud-navmenu.mud-navmenu-default .mud-nav-link.active .mud-nav-link-icon {
    color: #FFFFFF;
}

.r360-console .mud-nav-link.active .mud-nav-link-text {
    margin: 0;
    width: auto;
}

.r360-console__status {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    margin-inline-start: 2px;
    padding-inline-start: 8px;
    border-inline-start: 1px solid var(--r360-hairline);
}

.mud-button-root.r360-sync-trigger {
    min-width: 0;
    min-height: 40px;
    padding: 0 12px;
    border-radius: 14px;
    background-color: transparent;
}

.mud-button-root.r360-sync-trigger:hover {
    background-color: var(--r360-surface-2);
}

/* ── The launcher sheet — the same links, opened out ─────────────────────────────────────────── */

.r360-console-scrim {
    position: fixed;
    inset: 0;
    z-index: 1150;
    background-color: var(--mud-palette-overlay-dark);
    animation: r360-fade var(--r360-speed-base) var(--r360-ease) both;
}

.r360-console--open {
    width: min(68rem, calc(100vw - 2 * var(--r360-console-gap)));
}

.r360-console--open .r360-console__nav {
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(100% + 10px);
    max-height: calc(100vh - var(--r360-console-h) - 3 * var(--r360-console-gap) - 10px);
    margin: 0;
    padding: var(--r360-space-5);
    overflow: auto;
    pointer-events: auto;
    background-color: var(--r360-surface);
    border: 1px solid var(--r360-hairline);
    border-radius: 22px;
    box-shadow: var(--r360-shadow-3);
    animation: r360-sheet-in var(--r360-speed-slow) var(--r360-ease) both;
}

.r360-console--open .r360-console__nav .mud-navmenu {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
    align-items: start;
    gap: var(--r360-space-5) var(--r360-space-4);
}

.r360-console--open .mud-navmenu .mud-nav-item {
    width: 100%;
}

.r360-console--open .r360-nav-section {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    margin: 0;
    padding: 0;
    border: 0;
}

.r360-console--open .r360-nav-section__label {
    display: block;
    margin: 0 0 6px;
    padding: 0 10px;
    color: var(--r360-ink-muted);
}

.r360-console--open .mud-navmenu.mud-navmenu-default .mud-nav-link,
.r360-console--open .mud-navmenu.mud-navmenu-default .mud-nav-link.active:not(.mud-nav-link-disabled) {
    width: 100%;
    height: 40px;
    justify-content: flex-start;
    gap: 10px;
    padding: 0 10px;
    border-radius: var(--r360-radius-control);
    font-weight: 500;
    color: var(--r360-ink);
}

.r360-console--open .mud-navmenu.mud-navmenu-default .mud-nav-link .mud-nav-link-icon {
    color: var(--r360-mod-ink);
}

.r360-console--open .r360-nav-section__label {
    color: var(--r360-mod-ink);
}

.r360-console--open .mud-navmenu.mud-navmenu-default .mud-nav-link.active:not(.mud-nav-link-disabled) {
    color: #FFFFFF;
    font-weight: 600;
}

.r360-console--open .mud-navmenu.mud-navmenu-default .mud-nav-link.active .mud-nav-link-icon {
    color: #FFFFFF;
}

.r360-console--open .mud-nav-link .mud-nav-link-text {
    margin: 0;
    width: auto;
}

@keyframes r360-sheet-in {
    from { opacity: 0; transform: translateY(12px) scale(0.985); }
    to { opacity: 1; transform: none; }
}

@keyframes r360-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* Narrow screens: the strip cannot hold icons, so the console is launcher + the active pill +
   the connection state, and the sheet is the navigator. Same DOM — the resting links are hidden,
   not removed. */
@media (max-width: 960px) {
    .r360-console:not(.r360-console--open) .mud-nav-item:not(:has(.mud-nav-link.active)) {
        display: none;
    }

    .r360-console:not(.r360-console--open) .r360-nav-section {
        margin: 0;
        padding: 0;
        border: 0;
    }
}

/* ── The stage ───────────────────────────────────────────────────────────────────────────────── */

.r360-stage {
    display: block;
    width: 100%;
    max-width: 1520px;
    margin-inline: auto;
    padding: var(--r360-space-5) var(--r360-space-6) calc(var(--r360-console-h) + var(--r360-console-gap) + var(--r360-space-7));
}

@media (max-width: 760px) {
    .r360-stage {
        padding-inline: var(--r360-space-3);
    }
}

/* Snackbars must clear the console rather than land on it. */
.mud-snackbar-location-bottom-left,
.mud-snackbar-location-bottom-center,
.mud-snackbar-location-bottom-right {
    bottom: calc(var(--r360-console-h) + var(--r360-console-gap) + 12px);
}

/* ── Surfaces ────────────────────────────────────────────────────────────────────────────────── */

.mud-paper {
    border-radius: var(--r360-radius-panel);
    background-image: none;
}

.mud-dialog {
    border-radius: var(--r360-radius-modal);
    border: 1px solid var(--r360-hairline);
    box-shadow: var(--mud-elevation-24);
}

.mud-popover {
    border-radius: 14px;
    border: 1px solid var(--r360-hairline);
    box-shadow: var(--r360-shadow-3);
}

.mud-popover .mud-list {
    padding: 5px;
}

.mud-list-item {
    border-radius: 9px;
}

.mud-tooltip {
    border-radius: 8px;
    font-weight: 600;
}

.mud-divider {
    border-color: var(--r360-hairline);
}

/* [-] A global link-colour rule was here and is gone: MudBlazor paints a Color.Primary link with
   `.mud-primary-text { color: ... !important }`, so the rule never applied. Links take the accent
   itself, which measures 5.20:1 on a surface and 4.62:1 on the canvas — AA either way. */

/* ── Buttons ─────────────────────────────────────────────────────────────────────────────────────
   The CTA is ink. MudBlazor paints Color.Primary filled buttons from --mud-palette-primary, which
   in this system is the ACCENT — so the filled-primary button is restated from the --r360-cta pair
   here. :not(:disabled), so the disabled treatment of MudBlazor still wins when it should. */

.mud-button-root {
    border-radius: var(--r360-radius-control);
    text-transform: none;
    letter-spacing: 0;
}

.mud-button-root.mud-button {
    min-height: 40px;
    padding-inline: 16px;
}

.mud-button-root.mud-button.mud-button-text-size-small,
.mud-button-root.mud-button.mud-button-outlined-size-small,
.mud-button-root.mud-button.mud-button-filled-size-small {
    min-height: 32px;
    padding-inline: 12px;
    border-radius: 8px;
}

.mud-button-filled,
.mud-button-filled:hover {
    box-shadow: none;
}

/* [Aurora] The filled primary is the MODULE's gradient on its solid -a stop: an indigo-to-violet
   button on Home, sunset on the till, teal on stock. Outside the stage (a dialog, a menu) the
   start module's values at :root make it the brand gradient. */
.mud-button-filled.mud-button-filled-primary:not(:disabled) {
    background-color: var(--r360-mod-a);
    background-image: var(--r360-mod-fill);
    color: #FFFFFF;
    box-shadow: 0 6px 16px -8px var(--r360-mod-glow), inset 0 1px 0 rgba(255, 255, 255, 0.18);
    transition: box-shadow var(--r360-speed-base) var(--r360-ease), filter var(--r360-speed-base) var(--r360-ease), transform var(--r360-speed-fast) var(--r360-ease);
}

.mud-button-filled.mud-button-filled-primary:not(:disabled):hover {
    background-color: var(--r360-mod-a);
    filter: saturate(1.15) brightness(1.04);
    box-shadow: 0 12px 26px -10px var(--r360-mod-glow), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}

.mud-button-filled.mud-button-filled-primary:not(:disabled) .mud-progress-circular {
    color: #FFFFFF;
}

.mud-button-outlined {
    border-width: 1px;
    border-color: var(--r360-hairline-strong);
    background-color: var(--r360-surface);
}

.mud-button-outlined.mud-button-outlined-default,
.mud-button-outlined.mud-button-outlined-primary {
    color: var(--r360-ink);
    border-color: var(--r360-hairline-strong);
}

.mud-button-outlined.mud-button-outlined-default:hover,
.mud-button-outlined.mud-button-outlined-primary:hover {
    background-color: var(--r360-surface-2);
    border-color: var(--r360-ink-faint);
}

.mud-button-text.mud-button-text-primary {
    color: var(--r360-accent-text);
}

.mud-button-root.mud-button:active:not(:disabled) {
    transform: scale(0.98);
}

.mud-icon-button {
    border-radius: 12px;
}

/* [!] A toggle group is a SEGMENTED CONTROL. `Variant.Outlined` on a MudButtonGroup styles the
   group; the chosen child is only marked by Color.Primary, and the group-override rule of MudBlazor
   — `.mud-button-group-root.mud-button-group-override-styles .mud-button-root`, (0,3,0) — then
   paints every child the same. Eleven pages use this idiom, so the selected state is drawn once
   here, at (0,4,0): a soft inset track, and the chosen segment lifted onto the surface. */
.mud-button-group-root.mud-button-group-override-styles {
    display: inline-flex;
    /* Several pages pass d-block, which would stretch the track across the column. */
    width: fit-content;
    max-width: 100%;
    gap: 2px;
    padding: 3px;
    background-color: var(--r360-canvas-inset);
    border: 0;
    border-radius: 12px;
    box-shadow: none;
}

.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button {
    min-height: 32px;
    padding-inline: 14px;
    border: 0;
    border-radius: 9px;
    background-color: transparent;
    color: var(--r360-ink-muted);
    font-weight: 600;
    box-shadow: none;
}

.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button:hover {
    color: var(--r360-ink);
    background-color: transparent;
}

.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button-text-primary,
.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button-outlined-primary,
.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button-filled-primary,
.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button-text-primary:hover,
.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button-outlined-primary:hover,
.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button-filled-primary:hover {
    background-color: var(--r360-surface);
    background-image: none;
    color: var(--r360-mod-ink);
    box-shadow: var(--r360-shadow-1), inset 0 -2px 0 var(--r360-mod-c);
    filter: none;
}

/* ── Fields ──────────────────────────────────────────────────────────────────────────────────────
   The single largest change in how this product reads. MudBlazor draws a Material field: a label
   floating inside an outlined box and shrinking into a notch. Kaunta draws a STATIC label above a
   soft filled field — and it does so without touching the 250-odd `Variant.Outlined` usages, by
   re-laying-out the same elements:

     .mud-input-control-input-container   becomes a column
     label.mud-input-label-outlined       goes static, first in the column (order:-1)
     fieldset legend                      is removed, so there is no notch
     .mud-input.mud-input-outlined        gets the fill and the radius

   [!] The label transform carries !important, and it is the one place in this file that does. The
   MudBlazor shrink rule is `.mud-input:focus-within ~ label.mud-input-label.mud-input-label-outlined`
   and its siblings, at up to (0,5,1), with margin- and density-specific variants beside it; out-
   specifying every one is a fight this file would lose at each upgrade. A static label has exactly
   one correct transform — none — so it is said once and finally. */

.mud-input-control > .mud-input-control-input-container {
    display: flex;
    flex-direction: column;
}

.mud-input-control > .mud-input-control-input-container > label.mud-input-label-outlined,
.mud-input-control > .mud-input-control-input-container > label.mud-input-label-filled {
    position: static;
    order: -1;
    transform: none !important;
    max-width: 100%;
    margin: 0 0 6px 2px;
    padding: 0;
    background: none;
    color: var(--r360-ink-muted);
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    pointer-events: auto;
    z-index: auto;
}

.mud-input-control:focus-within > .mud-input-control-input-container > label.mud-input-label-outlined {
    color: var(--r360-accent-text);
}

.mud-input-control > .mud-input-control-input-container > label.mud-input-label-outlined.mud-input-error {
    color: var(--r360-failure-text);
}

.mud-input-control.mud-input-control-margin-normal,
.mud-input-control.mud-input-control-margin-normal.mud-input-outlined-with-label,
.mud-input-control.mud-input-control-margin-dense,
.mud-input-control.mud-input-control-margin-dense.mud-input-outlined-with-label {
    margin: 4px 0 2px;
}

.mud-input.mud-input-outlined {
    font-size: 0.875rem;
    background-color: var(--r360-surface-2);
    border-radius: var(--r360-radius-control);
    transition: background-color var(--r360-speed-fast) var(--r360-ease);
}

.mud-input.mud-input-outlined > .mud-input-outlined-border {
    top: 0;
    border: 1px solid var(--r360-hairline-strong);
    border-radius: var(--r360-radius-control);
    transition: border-color var(--r360-speed-fast) var(--r360-ease), box-shadow var(--r360-speed-fast) var(--r360-ease);
}

.mud-input.mud-input-outlined > .mud-input-outlined-border > legend {
    display: none;
}

.mud-input.mud-input-outlined.mud-shrink > .mud-input-outlined-border,
.mud-input.mud-input-outlined:focus-within > .mud-input-outlined-border {
    border-width: 1px;
}

.mud-input.mud-input-outlined:not(.mud-disabled):not(:focus-within):hover > .mud-input-outlined-border {
    border-color: var(--r360-ink-faint);
}

.mud-input.mud-input-outlined:focus-within {
    background-color: var(--r360-surface);
}

.mud-input-control .mud-input.mud-input-outlined:focus-within > .mud-input-outlined-border {
    border-color: var(--r360-accent);
    box-shadow: 0 0 0 3px var(--r360-ring);
}

.mud-input.mud-input-outlined.mud-input-error > .mud-input-outlined-border {
    border-color: var(--r360-failure);
}

.mud-input.mud-input-outlined > input.mud-input-root-outlined,
.mud-input.mud-input-outlined > div.mud-input-slot.mud-input-root-outlined {
    box-sizing: border-box;
    height: var(--r360-field-h);
    padding: 0 12px;
    line-height: var(--r360-field-h);
}

.mud-input.mud-input-outlined > textarea.mud-input-root-outlined {
    padding: 10px 12px;
}

.mud-input.mud-input-outlined.mud-input-adorned-end > input.mud-input-root-outlined {
    padding-inline-end: 4px;
}

.mud-input.mud-input-outlined.mud-input-adorned-start > input.mud-input-root-outlined {
    padding-inline-start: 4px;
}

/* With a static label there is nothing for a placeholder to collide with, so it is always shown. */
.mud-input > input.mud-input-root::placeholder,
.mud-input > textarea.mud-input-root::placeholder {
    color: var(--r360-ink-faint);
    opacity: 1 !important;
}

.mud-input-helper-text {
    margin-top: 4px;
    font-size: 0.75rem;
}

/* The ring is the focus indicator for a field; a second outline on the input inside it is noise. */
.mud-input > input.mud-input-root:focus-visible,
.mud-input > textarea.mud-input-root:focus-visible {
    outline: none;
}

/* ── Tags, alerts, skeletons ─────────────────────────────────────────────────────────────────── */

.mud-chip,
.mud-chip.mud-chip-size-small,
.mud-chip.mud-chip-size-medium,
.mud-chip.mud-chip-size-large {
    border-radius: var(--r360-radius-pill);
    font-weight: 600;
    font-size: 0.75rem;
    box-shadow: none;
}

.mud-chip.mud-chip-size-small {
    height: 24px;
    padding-inline: 10px;
}

/* A status tag is a tinted ground with text-safe words. The word is always there (NFR-UX-04: never
   colour alone); the tint is how an operator finds the row before reading it. */
.mud-chip-filled.mud-chip-color-success {
    background-color: var(--r360-confirmed-bg);
    color: var(--r360-confirmed-text);
}

.mud-chip-filled.mud-chip-color-warning {
    background-color: var(--r360-attention-bg);
    color: var(--r360-attention-text);
}

.mud-chip-filled.mud-chip-color-error {
    background-color: var(--r360-failure-bg);
    color: var(--r360-failure-text);
}

.mud-chip-filled.mud-chip-color-primary {
    background-color: var(--r360-accent-soft);
    color: var(--r360-accent-text);
}

.mud-chip-filled.mud-chip-color-info,
.mud-chip-filled.mud-chip-color-default {
    background-color: var(--r360-canvas-inset);
    color: var(--r360-ink-muted);
}

.mud-chip-filled .mud-chip-icon {
    color: inherit;
}

.mud-alert {
    border-radius: 14px;
    box-shadow: none;
}

.mud-skeleton {
    border-radius: 8px;
}

.mud-skeleton.mud-skeleton-wave::after,
.mud-skeleton.mud-skeleton-pulse {
    animation-duration: 1.4s;
}

.mud-switch-base.mud-checked + .mud-switch-track {
    opacity: 1;
}

.mud-progress-linear {
    border-radius: var(--r360-radius-pill);
    overflow: hidden;
}

/* ── Tables ──────────────────────────────────────────────────────────────────────────────────────
   Header: a quiet band in sentence case. Rows: hairlines and a hover tint — zebra stays retired,
   because the only banded colour on a worklist should be the status of the row.

   [!] Two selector families throughout: MudTable cells are `.mud-table-cell` and MudSimpleTable
   cells are bare td/th under `.mud-simple-table table * tr > td` at (0,1,3). Anything written once
   silently misses half the product. */
.mud-table-root .mud-table-head th.mud-table-cell,
.mud-table-root .mud-table-head .mud-table-cell,
.mud-simple-table table thead tr > th {
    font-family: var(--r360-font-ui);
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: none;
    letter-spacing: 0.01em;
    line-height: 1.4;
    color: var(--r360-ink-muted);
    background-color: var(--r360-mod-soft);
    border-bottom: 1px solid var(--r360-hairline);
    padding-top: 10px;
    padding-bottom: 10px;
    white-space: nowrap;
}

.mud-table-root .mud-table-head tr > th:first-child,
.mud-simple-table table thead tr > th:first-child {
    border-start-start-radius: var(--r360-radius-control);
    border-end-start-radius: var(--r360-radius-control);
}

.mud-table-root .mud-table-head tr > th:last-child,
.mud-simple-table table thead tr > th:last-child {
    border-start-end-radius: var(--r360-radius-control);
    border-end-end-radius: var(--r360-radius-control);
}

.mud-table-row td,
.mud-simple-table table tbody tr > td {
    border-bottom: 1px solid var(--mud-palette-table-lines);
    height: var(--r360-row-h);
    padding-top: var(--r360-cell-pad-y);
    padding-bottom: var(--r360-cell-pad-y);
    font-size: var(--r360-text-body);
}

.mud-table-row:hover,
.mud-simple-table tbody tr:hover {
    background-color: var(--mud-palette-table-hover);
}

.mud-table-row:last-child td,
.mud-simple-table table tbody tr:last-child > td {
    border-bottom: 0;
}

.mud-table.mud-paper,
.mud-simple-table.mud-paper {
    background-color: transparent;
    box-shadow: none;
    border-radius: 0;
}

/* ── Shared components ───────────────────────────────────────────────────────────────────────────
   HOUSE RULE: a selector targeting the ROOT element of a MudBlazor component belongs here, never
   in a .razor.css. `::deep X` compiles to `[scope] X` — a descendant combinator needing an
   ancestor with the scope attribute — and the compiler stamps that attribute onto HTML elements
   only. A class passed via Class="" onto <MudPaper> is on the component root, so there is nothing
   above it to descend from and the rule matches nothing, silently. Audit:
       grep -rn '^\[b-' src/Retail360.Web.Client/obj/Debug/net10.0/scopedcss/ */

/* [Aurora] A panel: the surface, a faint wash of the module's hue in the top-right corner, and a
   3px band of its bright gradient along the top edge. All three are background layers over a solid
   background-color, and the edge is painted INTO the border box — so there is no pseudo-element to
   position and no overflow:hidden to clip a popover. */
.r360-section {
    background-color: var(--r360-surface);
    background-image:
        linear-gradient(90deg, var(--r360-mod-c), var(--r360-mod-d)),
        radial-gradient(30rem 14rem at 100% 0%, var(--r360-mod-wash), transparent 70%),
        linear-gradient(var(--r360-surface), var(--r360-surface)),
        linear-gradient(var(--r360-hairline), var(--r360-hairline));
    background-size: 100% 3px, auto, auto, auto;
    background-position: top, 0 0, 0 0, 0 0;
    background-repeat: no-repeat;
    background-origin: border-box, padding-box, padding-box, border-box;
    background-clip: border-box, padding-box, padding-box, border-box;
    border: 1px solid transparent;
    border-top-width: 3px;
    border-radius: var(--r360-radius-panel);
    box-shadow: var(--r360-shadow-1);
    padding: 0;
    margin-bottom: var(--r360-space-5);
    animation: r360-rise var(--r360-speed-slow) var(--r360-ease) both;
}

.r360-section .r360-section__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--r360-space-3);
    flex-wrap: wrap;
    margin: 0;
    padding: 18px var(--r360-space-5) 0;
}

.r360-section .r360-section__body {
    padding: var(--r360-space-5);
}

.r360-section .r360-section__header + .r360-section__body {
    padding-top: var(--r360-space-4);
}

.r360-section--dense {
    margin-bottom: var(--r360-space-4);
}

.r360-section--dense .r360-section__header {
    padding: 14px var(--r360-space-4) 0;
}

.r360-section--dense .r360-section__body {
    padding: var(--r360-space-4);
}

/* The icon tile: the SVG itself carries the padding, the tint and the radius. */
.r360-section__icon.mud-icon-root {
    box-sizing: border-box;
    width: 32px;
    height: 32px;
    padding: 6px;
    border-radius: 10px;
    background-color: var(--r360-mod-a);
    background-image: var(--r360-mod-fill);
    color: #FFFFFF;
    box-shadow: 0 6px 14px -6px var(--r360-mod-glow);
}

.r360-stat-card {
    position: relative;
    background-color: var(--r360-surface);
    background-image:
        linear-gradient(90deg, var(--r360-mod-c), var(--r360-mod-d)),
        radial-gradient(18rem 10rem at 100% 0%, var(--r360-mod-wash), transparent 72%),
        linear-gradient(var(--r360-surface), var(--r360-surface)),
        linear-gradient(var(--r360-hairline), var(--r360-hairline));
    background-size: 100% 3px, auto, auto, auto;
    background-position: top, 0 0, 0 0, 0 0;
    background-repeat: no-repeat;
    background-origin: border-box, padding-box, padding-box, border-box;
    background-clip: border-box, padding-box, padding-box, border-box;
    padding: var(--r360-space-5);
    border: 1px solid transparent;
    border-top-width: 3px;
    transition: transform var(--r360-speed-base) var(--r360-ease), box-shadow var(--r360-speed-base) var(--r360-ease);
    border-radius: var(--r360-radius-panel);
    box-shadow: var(--r360-shadow-1);
    height: 100%;
    display: flex;
    flex-direction: column;
    gap: var(--r360-space-2);
    animation: r360-rise var(--r360-speed-slow) var(--r360-ease) both;
}

.r360-stat-card__value.mud-typography {
    font-family: var(--r360-font-display);
    font-variant-numeric: tabular-nums;
    font-size: clamp(1.25rem, 1.9vw, 1.75rem);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.03em;
    margin: 0;
    overflow-wrap: anywhere;
}

.r360-stat-card__sentence {
    color: var(--r360-ink-muted);
}

/* ── Page-level classes that sit on a component root ─────────────────────────────────────────── */

.r360-org-actions,
.r360-net-stats,
.r360-dq-filters {
    row-gap: var(--r360-space-2);
}

.r360-section.r360-search-hero .r360-section__body {
    padding-block: var(--r360-space-6);
}

/* A toolbar of filters and one action. Was copy-pasted into three page stylesheets, where its
   field rules also needed ::deep; its children are MudBlazor roots, so it lives here. */
.r360-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--r360-space-3);
}

.r360-toolbar .r360-toolbar__field {
    flex: 1 1 12rem;
    min-width: 10rem;
}

.r360-toolbar .r360-toolbar__action {
    flex: 0 0 auto;
    margin-bottom: 2px;
}

/* ── Islands' tenants: the branch pill and the user trigger ──────────────────────────────────── */

.mud-button-root.r360-branch {
    gap: 8px;
    min-height: 36px;
    padding-inline: 8px 10px;
    border-radius: 12px;
    color: var(--r360-ink);
}

.r360-branch__code {
    font-family: var(--r360-font-mono);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    line-height: 1;
    padding: 5px 7px;
    border-radius: 7px;
    background-color: var(--r360-accent-soft);
    color: var(--r360-accent-text);
}

.r360-branch__name {
    font-size: 0.8125rem;
    font-weight: 600;
    white-space: nowrap;
    max-width: 12rem;
    overflow: hidden;
    text-overflow: ellipsis;
}

.r360-branch__code--menu {
    background-color: var(--r360-canvas-inset);
    color: var(--r360-ink-muted);
    margin-inline-end: 8px;
}

.r360-user-menu__trigger .mud-button-label,
.r360-branch .mud-button-label {
    gap: 8px;
}

.mud-button-root.r360-user-menu__trigger {
    gap: 8px;
    min-height: 36px;
    padding-inline: 5px 10px;
    border-radius: 12px;
    color: var(--r360-ink);
}

@media (max-width: 1100px) {
    .r360-branch__name,
    .r360-user-menu__trigger [data-testid="user-menu-name"] {
        display: none;
    }
}

/* ── Part photos on the parts screen ───────────────────────────────────────────────────────────
   Global rather than scoped: the cell is a MudTd, a component, so a scoped rule has no ancestor to
   hang from (ui-conventions §2). The thumbnail sits on white in both themes, because a photo shot on
   a bench is a light picture and a dark well around it reads as a hole in the table. */

.r360-photo {
    display: flex;
    align-items: center;
    gap: 10px;
}

.r360-photo__thumb {
    width: 48px;
    height: 48px;
    flex: none;
    object-fit: contain;
    background: #FFFFFF;
    border: 1px solid var(--r360-hairline);
    border-radius: var(--r360-radius-control);
}

.r360-photo__thumb--none {
    display: grid;
    place-items: center;
    background: transparent;
    border-style: dashed;
    color: var(--r360-ink-muted);
}

.r360-photo__actions {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    font-size: 0.8125rem;
}

.r360-photo__pick,
.r360-photo__remove {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: var(--r360-primary);
    cursor: pointer;
    white-space: nowrap;
}

.r360-photo__remove { color: var(--r360-ink-muted); }

.r360-photo__pick:hover,
.r360-photo__remove:hover { text-decoration: underline; }

/* The file input is visually hidden but still takes focus, so the label shows where focus is. */
.r360-photo__pick:focus-within {
    outline: 2px solid var(--r360-primary);
    outline-offset: 2px;
    border-radius: 4px;
}

.r360-photo__pick--busy { opacity: 0.6; cursor: progress; }

/* ── Numerals and identifiers ────────────────────────────────────────────────────────────────── */

.r360-visually-hidden {
    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;
}

/* One treatment, three names — so a reader of a .razor file can tell a stock figure from a price
   without opening a stylesheet. */
.r360-num,
.r360-money,
.r360-qty {
    font-family: var(--r360-font-mono);
    font-variant-numeric: tabular-nums slashed-zero;
    text-align: right;
    letter-spacing: -0.02em;
}

.r360-id {
    font-family: var(--r360-font-mono);
    font-variant-numeric: slashed-zero;
    letter-spacing: -0.01em;
}

/* THE PART-NUMBER SPECIMEN. Everything downstream hangs off this string — stock, price, fitment —
   so it is set as a specimen wherever it appears and never truncates; the description gives way. */
.r360-partno {
    font-family: var(--r360-font-mono);
    font-variant-numeric: slashed-zero tabular-nums;
    font-weight: 600;
    font-size: 0.8125rem;
    letter-spacing: 0;
    color: var(--r360-ink);
    white-space: nowrap;
}

/* [!] The same rules again at (0,2,3), and it is not duplication for its own sake: MudSimpleTable
   states cell font and alignment as `.mud-simple-table table * tr > td` — (0,1,3) — which beats
   every single-class utility above. Without these, every <td>-based table in the product ignores
   the numeric classes, the till total included. */
.mud-simple-table table tbody tr > td.r360-num,
.mud-simple-table table tbody tr > td.r360-money,
.mud-simple-table table tbody tr > td.r360-qty {
    font-family: var(--r360-font-mono);
    font-variant-numeric: tabular-nums slashed-zero;
    text-align: right;
    letter-spacing: -0.02em;
}

.mud-simple-table table tbody tr > td.r360-partno {
    font-family: var(--r360-font-mono);
    font-variant-numeric: slashed-zero tabular-nums;
    font-weight: 600;
    font-size: 0.8125rem;
    letter-spacing: 0;
    color: var(--r360-ink);
    white-space: nowrap;
}

.mud-simple-table table tbody tr > td.r360-id {
    font-family: var(--r360-font-mono);
    font-variant-numeric: slashed-zero;
}

/* [!] And a THIRD time, for MudTable — measured in the browser, because the earlier pass assumed
   these cells tied with the utilities and won on source order. They do not: MudBlazor states body
   cells as `.mud-table-root .mud-table-body .mud-table-cell`, (0,3,0), which beats a single class.
   So every MudTable in the product (Parts, Stock, Pricing, Vehicles) was drawing part numbers and
   money in the proportional UI face. (0,4,0) wins it back. */
.mud-table-root .mud-table-body .mud-table-cell.r360-num,
.mud-table-root .mud-table-body .mud-table-cell.r360-money,
.mud-table-root .mud-table-body .mud-table-cell.r360-qty {
    font-family: var(--r360-font-mono);
    font-variant-numeric: tabular-nums slashed-zero;
    text-align: right;
    letter-spacing: -0.02em;
}

.mud-table-root .mud-table-body .mud-table-cell.r360-partno {
    font-family: var(--r360-font-mono);
    font-variant-numeric: slashed-zero tabular-nums;
    font-weight: 600;
    font-size: 0.8125rem;
    letter-spacing: 0;
    color: var(--r360-ink);
    white-space: nowrap;
}

.mud-table-root .mud-table-body .mud-table-cell.r360-id {
    font-family: var(--r360-font-mono);
    font-variant-numeric: slashed-zero;
}

.mud-simple-table table thead tr > th.r360-num,
.mud-simple-table table thead tr > th.r360-money,
.mud-simple-table table thead tr > th.r360-qty,
.mud-table-root .mud-table-head th.r360-num,
.mud-table-root .mud-table-head th.r360-money,
.mud-table-root .mud-table-head th.r360-qty {
    text-align: right;
}

/* A keycap, for a shortcut named in the interface. */
.r360-kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    height: 1.375rem;
    padding: 0 6px;
    border: 1px solid var(--r360-hairline-strong);
    border-bottom-width: 2px;
    border-radius: 6px;
    background-color: var(--r360-surface-2);
    color: var(--r360-ink-muted);
    font-family: var(--r360-font-mono);
    font-size: 0.6875rem;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
}

/* The pegboard — behind the sign-in and inside empty states. */
.r360-pegboard {
    background-image: radial-gradient(circle at 1px 1px, var(--r360-peg) 1px, transparent 1.5px);
    background-size: 24px 24px;
}

/* ── Motion ──────────────────────────────────────────────────────────────────────────────────────
   Content RISES into place when a page mounts. A CSS animation fires on insertion only, so a
   re-render of an existing panel never replays it. Everything is switched off by the reduced-motion
   rule below. */
@keyframes r360-rise {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
}

.mud-button-root,
.mud-paper,
.mud-nav-link,
.mud-chip {
    transition: background-color var(--r360-speed-base) var(--r360-ease), box-shadow var(--r360-speed-base) var(--r360-ease), border-color var(--r360-speed-base) var(--r360-ease), color var(--r360-speed-base) var(--r360-ease), transform var(--r360-speed-fast) var(--r360-ease);
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

.r360-page {
    max-width: 1520px;
    margin-inline: auto;
}

* {
    scrollbar-width: thin;
    scrollbar-color: var(--mud-palette-lines-inputs) transparent;
}

/* ── Focus ───────────────────────────────────────────────────────────────────────────────────────
   :focus-visible, not :focus — the browser applies it to keyboard focus and withholds it from a
   tap, which stops a permanent outline appearing around every button touched on a till screen.

   It is an OUTLINE on the focused element itself, and that is a contract: ShellAccessibilityTests
   tabs to nav-toggle and requires an outline or a box-shadow on that element. The accent, offset
   by 2px so it reads against an ink button, a white capsule and the canvas alike. */
.mud-button-root:focus-visible,
.mud-nav-link:focus-visible,
.mud-input-control:focus-visible,
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--r360-accent);
    outline-offset: 2px;
}

/* The router moves focus to the page heading on navigation (FocusOnNavigate). That focus is
   programmatic, so it should not paint a ring around the title. */
h1:focus,
h1:focus-visible {
    outline: none;
}

/* ── Legacy framework hooks — kept because something still uses them ────────────────────────── */

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--r360-confirmed);
}

.invalid {
    outline: 1px solid var(--r360-failure);
}

.validation-message {
    color: var(--r360-failure-text);
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

/* ── Account security (FR-IAM-04) ──────────────────────────────────────────
   .sec-code sits on a MudTextField, so it is here rather than in
   AccountSecurity.razor.css: a scoped rule compiles to `.sec-code[b-xxx]` and
   the scope attribute is never stamped on a component tag. Six digits typed
   off a phone want a short field and mono figures, not a full-width input. */
.sec-code {
    max-width: 12rem;
}

.sec-code input {
    font-family: var(--r360-font-mono);
    font-size: 1.125rem;
    letter-spacing: 0.22em;
}

/* ── Support module ────────────────────────────────────────────────────────
   All in app.css rather than scoped files, for two reasons the ::deep trap
   makes non-negotiable: these classes are shared across three components
   (Support, SupportArticlePage, SupportBlockView), and .sup-search sits on a
   MudTextField — a scoped rule compiles to `.sup-x[b-id]` and that attribute
   is never stamped on a component tag. */

.sup-lead,
.sup-summary {
    margin: 0 0 var(--r360-space-4);
    color: var(--r360-ink-muted);
    max-width: 68ch;
}

.sup-summary {
    font-size: 1.0625rem;
    color: var(--r360-ink);
}

.sup-search { max-width: 34rem; }

.sup-count {
    margin: var(--r360-space-2) 0 0;
    font-size: 0.8125rem;
    color: var(--r360-ink-muted);
    font-variant-numeric: tabular-nums;
}

.sup-shelf {
    margin: 0 0 var(--r360-space-1);
    font-size: 1.0625rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.sup-shelf__blurb {
    margin: 0 0 var(--r360-space-3);
    color: var(--r360-ink-muted);
    font-size: 0.875rem;
    max-width: 68ch;
}

/* Cards fill the row they are in. A column count that leaves one card alone on
   the last row reads as a mistake. */
.sup-grid {
    display: grid;
    gap: var(--r360-space-2);
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
}

.sup-card {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: var(--r360-space-3);
    border: 1px solid var(--r360-hairline);
    border-radius: var(--r360-radius-panel);
    background: var(--r360-surface-2);
    color: inherit;
    text-decoration: none;
    transition: border-color var(--r360-speed-fast) var(--r360-ease);
}

.sup-card:hover,
.sup-card:focus-visible { border-color: var(--r360-primary); }

.sup-card__title { font-weight: 700; }

.sup-card__summary {
    color: var(--r360-ink-muted);
    font-size: 0.875rem;
    line-height: 1.45;
}

.sup-card__audience {
    margin-top: 4px;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--r360-ink-muted);
}

/* ── article body ───────────────────────────────────────────────── */

.sup-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--r360-space-2) var(--r360-space-4);
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: var(--r360-space-3);
    padding-bottom: var(--r360-space-2);
    border-bottom: 1px solid var(--r360-hairline);
}

.sup-meta__audience {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--r360-ink-muted);
}

.sup-back { color: var(--r360-primary); text-decoration: none; font-weight: 600; }
.sup-back:hover { text-decoration: underline; }

.sup-body { display: block; max-width: 72ch; }

.sup-para { margin: 0 0 var(--r360-space-3); line-height: 1.65; }

.sup-heading {
    margin: var(--r360-space-5) 0 var(--r360-space-2);
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--r360-ink-muted);
}

.sup-body > :first-child { margin-top: 0; }

.sup-steps,
.sup-bullets { margin: 0 0 var(--r360-space-3); padding-left: 1.4em; }

.sup-steps li,
.sup-bullets li { margin-bottom: 6px; line-height: 1.6; }

/* Callouts carry a WORD as well as a colour — NFR-UX-04. The tint is the
   second, redundant signal. */
.sup-callout {
    display: grid;
    gap: 4px;
    margin: 0 0 var(--r360-space-3);
    padding: var(--r360-space-2) var(--r360-space-3);
    border-left: 3px solid var(--r360-hairline);
    border-radius: 0 var(--r360-radius-control) var(--r360-radius-control) 0;
    background: var(--r360-surface-2);
    line-height: 1.6;
}

.sup-callout__label {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.01em;
}

.sup-callout--note { border-left-color: var(--r360-primary); }
.sup-callout--note .sup-callout__label { color: var(--r360-primary); }

.sup-callout--warning { border-left-color: var(--r360-attention); }
.sup-callout--warning .sup-callout__label { color: var(--r360-attention-text); }

.sup-callout--notbuilt { border-left-color: var(--r360-ink-muted); }
.sup-callout--notbuilt .sup-callout__label { color: var(--r360-ink-muted); }

.sup-screen {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--r360-space-2);
    margin: 0 0 var(--r360-space-3);
    padding: 8px var(--r360-space-3);
    border: 1px solid var(--r360-hairline);
    border-radius: var(--r360-radius-control);
    text-decoration: none;
    color: inherit;
}

.sup-screen:hover { border-color: var(--r360-primary); }
.sup-screen__label { font-weight: 600; color: var(--r360-primary); }

.sup-screen__route {
    font-family: var(--r360-font-mono);
    font-size: 0.75rem;
    color: var(--r360-ink-muted);
}

.sup-table {
    width: 100%;
    margin: 0 0 var(--r360-space-3);
    border-collapse: collapse;
}

.sup-table th,
.sup-table td {
    text-align: left;
    vertical-align: top;
    padding: 7px var(--r360-space-2) 7px 0;
    border-bottom: 1px solid var(--r360-hairline);
    line-height: 1.55;
}

.sup-table th { font-weight: 700; width: 34%; padding-right: var(--r360-space-3); }
.sup-table--keys th { width: 10rem; }

.sup-facts__caption {
    margin: 0 0 4px;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--r360-ink-muted);
}

.sup-kbd {
    display: inline-block;
    min-width: 2rem;
    padding: 2px 7px;
    border: 1px solid var(--r360-hairline);
    border-bottom-width: 2px;
    border-radius: 4px;
    background: var(--r360-surface-2);
    font-family: var(--r360-font-mono);
    font-size: 0.8125rem;
    text-align: center;
}

.sup-command { margin: 0 0 var(--r360-space-3); }

.sup-command__shell {
    display: inline-block;
    margin-bottom: 3px;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--r360-ink-muted);
}

/* A command scrolls rather than wrapping. A wrapped path or connection string
   is one somebody pastes wrong. */
.sup-command__text {
    margin: 0;
    padding: var(--r360-space-2) var(--r360-space-3);
    border: 1px solid var(--r360-hairline);
    border-radius: var(--r360-radius-control);
    background: var(--r360-surface-2);
    overflow-x: auto;
}

.sup-command__text code {
    font-family: var(--r360-font-mono);
    font-size: 0.8125rem;
    white-space: pre;
}

/* A runbook gets pinned to a wall. Drop the shell and keep the article. */
/* ── Queued with Phases B-D ──────────────────────────────────────────────────────────────────── */

/* A bare section: the title stays as a group label, the card does not. For panels whose content is
   already made of tiles (the dashboard stat groups), where a card around cards is a box in a box.
   On the MudPaper root, so it lives here rather than in a page stylesheet. */
.r360-section.r360-section--bare {
    background-color: transparent;
    background-image: none;
    border: 0;
    box-shadow: none;
}

.r360-section.r360-section--bare .r360-section__header {
    padding: 0 2px;
}

.r360-section.r360-section--bare .r360-section__body,
.r360-section.r360-section--bare .r360-section__header + .r360-section__body {
    padding: var(--r360-space-3) 0 0;
}

/* The completed-sale panel — a confirmed ticket. Applied via Class="" onto a MudPaper the till
   renders directly inside PermissionView, so there is no page-written element above it and a
   scoped rule could never reach it. */
.till-hero {
    max-width: 34rem;
    padding: var(--r360-space-6);
    margin-bottom: var(--r360-space-5);
    background-color: var(--r360-surface);
    border: 1px solid var(--r360-hairline);
    border-top: 4px solid var(--r360-confirmed);
    border-radius: var(--r360-radius-panel);
    box-shadow: var(--r360-shadow-2);
    animation: r360-rise var(--r360-speed-slow) var(--r360-ease) both;
}

/* ── Inline decision panels, a nested-card ground and an emphasised notice ─────────────────────
   Four rules that lived in page stylesheets as `::deep .x`, each targeting the ROOT of a MudPaper,
   MudAlert or SectionCard that the page renders inside another component — so there was no
   page-written element above it and the selector could never match (house rule 1). The previous
   pass listed them as "plausible, not individually verified"; they are settled here instead of
   measured one by one, because this is where such a rule belongs whatever the measurement says. */
.mud-paper.r360-leads-inline-panel,
.mud-paper.r360-enquiry-inline-panel {
    background-color: var(--r360-surface-2);
    border: 1px solid var(--r360-hairline);
    border-inline-start: 3px solid var(--r360-accent);
    border-radius: var(--r360-radius-control);
}

.mud-alert.returns-nothing-moved {
    border-inline-start: 3px solid var(--r360-ink-muted);
    font-weight: 600;
}

/* Cards inside the two outer Returns & Warranty panels sit on an inset ground, not as a second
   white card inside a white card. */
.r360-section.rw-outer-section .r360-section {
    background-color: var(--r360-surface-2);
    background-image: none;
    border: 1px solid var(--r360-hairline);
    box-shadow: none;
}

/* The till's small two-column figure tables (the completed-sale summary, the margin block). */
.mud-simple-table.till-summary {
    max-width: 22rem;
}

/* A risk row on the dashboard: a full-width pill, so a list of them reads as a list. */

.mud-chip.d-block {
    display: flex;
    width: 100%;
    max-width: 100%;
    height: auto;
    min-height: 36px;
    margin-inline: 0;
    padding: 8px 14px;
    border-radius: 12px;
    white-space: normal;
    justify-content: flex-start;
}

.mud-chip.d-block .mud-chip-content {
    white-space: normal;
    text-align: start;
    line-height: 1.35;
}

/* Variant.Text fields (the till quantity box, a few inline editors): the same soft field, without
   the Material underline. */
.mud-input.mud-input-text {
    background-color: var(--r360-surface-2);
    border: 1px solid var(--r360-hairline-strong);
    border-radius: var(--r360-radius-control);
    padding-inline: 10px;
    margin-top: 0;
}

.mud-input.mud-input-text.mud-input-underline::before,
.mud-input.mud-input-text.mud-input-underline::after {
    display: none;
}

.mud-input.mud-input-text:focus-within {
    background-color: var(--r360-surface);
    border-color: var(--r360-accent);
    box-shadow: 0 0 0 3px var(--r360-ring);
}

.mud-input-control > .mud-input-control-input-container > label.mud-input-label-text {
    position: static;
    order: -1;
    transform: none !important;
    max-width: 100%;
    margin: 0 0 6px 2px;
    padding: 0;
    color: var(--r360-ink-muted);
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.4;
}

/* Switches: a touch larger and clearly on in the accent. */
.mud-switch .mud-typography {
    font-size: 0.875rem;
}

/* Expansion panels (Organisation) as soft cards rather than Material accordions. */
.mud-expansion-panels .mud-expand-panel {
    border-radius: var(--r360-radius-panel) !important;
    border: 1px solid var(--r360-hairline);
    box-shadow: var(--r360-shadow-1);
    margin-bottom: var(--r360-space-3);
}

.mud-expansion-panels .mud-expand-panel::before {
    display: none;
}

/* Alerts: a soft tinted panel with text-safe words, in the same family as the status tags. */
.mud-alert.mud-alert-text-success { background-color: var(--r360-confirmed-bg); color: var(--r360-confirmed-text); }
.mud-alert.mud-alert-text-warning { background-color: var(--r360-attention-bg); color: var(--r360-attention-text); }
.mud-alert.mud-alert-text-error { background-color: var(--r360-failure-bg); color: var(--r360-failure-text); }
.mud-alert.mud-alert-text-info,
.mud-alert.mud-alert-text-normal { background-color: var(--r360-canvas-inset); color: var(--r360-ink); }
.mud-alert.mud-alert-text-success .mud-alert-icon { color: var(--r360-confirmed); }
.mud-alert.mud-alert-text-warning .mud-alert-icon { color: var(--r360-attention-text); }
.mud-alert.mud-alert-text-error .mud-alert-icon { color: var(--r360-failure); }
.mud-alert.mud-alert-text-info .mud-alert-icon { color: var(--r360-ink-muted); }

/* ── Aurora — module identity ────────────────────────────────────────────────────────────────────
   Every page and every console section says which module it belongs to (data-r360-module, set by
   MainLayout from NavigationCatalogue.ModuleFor and by NavSection from its key). Each block sets
   five raw hues; the DERIVED tokens are restated on every element that carries the attribute.

   [!] That restatement is the whole trick, not tidiness. A custom property whose value contains
   var() is resolved where it is DECLARED and inherited as the finished value — so a --r360-mod-fill
   declared once at :root would stay indigo for ever, whatever a child set --r360-mod-a to. Declared
   again on [data-r360-module], it is resolved against that element's own hues.

   The fill pair (-a/-b) is checked for WHITE text at 4.5:1 on both stops — which is why Sell's
   fill is #C2410C → #E11D48 and not the #FF7A18 → #FF3D77 of its bright pair: white on #FF7A18 is
   2.6:1. Bright pairs decorate; fill pairs carry words. */

:root,
[data-r360-module] {
    --r360-mod-fill: linear-gradient(135deg, var(--r360-mod-a) 0%, var(--r360-mod-b) 100%);
    --r360-mod-bright: linear-gradient(120deg, var(--r360-mod-c) 0%, var(--r360-mod-d) 100%);
    --r360-mod-soft: color-mix(in srgb, var(--r360-mod-c) 12%, var(--r360-surface));
    --r360-mod-wash: color-mix(in srgb, var(--r360-mod-d) 9%, transparent);
    --r360-mod-glow: color-mix(in srgb, var(--r360-mod-c) 55%, transparent);
    --r360-mod-ring: color-mix(in srgb, var(--r360-mod-c) 40%, transparent);
}

:root {
    --r360-glow-1: rgba(236, 72, 153, 0.13);
    --r360-glow-2: rgba(99, 102, 241, 0.14);
    --r360-glow-3: rgba(6, 182, 212, 0.11);
}

[data-r360-module="start"]     { --r360-mod-a: #4F46E5; --r360-mod-b: #7C3AED; --r360-mod-c: #6366F1; --r360-mod-d: #A855F7; --r360-mod-ink: #4338CA; }
[data-r360-module="sell"]      { --r360-mod-a: #C2410C; --r360-mod-b: #E11D48; --r360-mod-c: #FF7A18; --r360-mod-d: #FF3D77; --r360-mod-ink: #C2410C; }
[data-r360-module="catalogue"] { --r360-mod-a: #7C3AED; --r360-mod-b: #C026D3; --r360-mod-c: #8B5CF6; --r360-mod-d: #D946EF; --r360-mod-ink: #6D28D9; }
[data-r360-module="stock"]     { --r360-mod-a: #0F766E; --r360-mod-b: #0E7490; --r360-mod-c: #14B8A6; --r360-mod-d: #06B6D4; --r360-mod-ink: #0F766E; }
[data-r360-module="customers"] { --r360-mod-a: #2563EB; --r360-mod-b: #4F46E5; --r360-mod-c: #3B82F6; --r360-mod-d: #6366F1; --r360-mod-ink: #1D4ED8; }
[data-r360-module="insights"]  { --r360-mod-a: #9333EA; --r360-mod-b: #DB2777; --r360-mod-c: #A855F7; --r360-mod-d: #EC4899; --r360-mod-ink: #7E22CE; }
[data-r360-module="admin"]     { --r360-mod-a: #475569; --r360-mod-b: #4F46E5; --r360-mod-c: #64748B; --r360-mod-d: #6366F1; --r360-mod-ink: #334155; }
[data-r360-module="help"]      { --r360-mod-a: #0369A1; --r360-mod-b: #4F46E5; --r360-mod-c: #0EA5E9; --r360-mod-d: #6366F1; --r360-mod-ink: #0369A1; }
[data-r360-module="orders"]    { --r360-mod-a: #047857; --r360-mod-b: #15803D; --r360-mod-c: #10B981; --r360-mod-d: #84CC16; --r360-mod-ink: #047857; }

/* Dark: the fills stay (white still reads on them) but the text-safe ink has to turn LIGHT, and
   no single color-mix is both darker than a hue on white and lighter than it on near-black while
   staying vivid — hence data-r360-theme, written by MainLayout beside data-r360-density. */
:root[data-r360-theme="dark"] {
    --r360-mod-ink: #A5B4FC;
    --r360-glow-1: rgba(236, 72, 153, 0.16);
    --r360-glow-2: rgba(99, 102, 241, 0.22);
    --r360-glow-3: rgba(6, 182, 212, 0.12);
}

:root[data-r360-theme="dark"] [data-r360-module="start"]     { --r360-mod-ink: #A5B4FC; }
:root[data-r360-theme="dark"] [data-r360-module="sell"]      { --r360-mod-ink: #FDBA74; }
:root[data-r360-theme="dark"] [data-r360-module="catalogue"] { --r360-mod-ink: #D8B4FE; }
:root[data-r360-theme="dark"] [data-r360-module="stock"]     { --r360-mod-ink: #5EEAD4; }
:root[data-r360-theme="dark"] [data-r360-module="customers"] { --r360-mod-ink: #93C5FD; }
:root[data-r360-theme="dark"] [data-r360-module="insights"]  { --r360-mod-ink: #F0ABFC; }
:root[data-r360-theme="dark"] [data-r360-module="admin"]     { --r360-mod-ink: #CBD5E1; }
:root[data-r360-theme="dark"] [data-r360-module="help"]      { --r360-mod-ink: #7DD3FC; }
:root[data-r360-theme="dark"] [data-r360-module="orders"]    { --r360-mod-ink: #6EE7B7; }

:root[data-r360-theme="dark"],
:root[data-r360-theme="dark"] [data-r360-module] {
    --r360-mod-soft: color-mix(in srgb, var(--r360-mod-c) 20%, var(--r360-surface));
    --r360-mod-wash: color-mix(in srgb, var(--r360-mod-d) 16%, transparent);
}

/* ── Aurora — the shell ──────────────────────────────────────────────────────────────────────── */

/* The console capsule: still an OPAQUE surface (the connectivity label is measured against it),
   edged with a hairline of the brand spectrum painted into its border box. */
.r360-console {
    border-color: transparent;
    background-image:
        linear-gradient(var(--r360-surface), var(--r360-surface)),
        linear-gradient(100deg, rgba(99, 102, 241, 0.55), rgba(236, 72, 153, 0.45) 50%, rgba(6, 182, 212, 0.5));
    background-origin: border-box;
    background-clip: padding-box, border-box;
    box-shadow: 0 20px 44px -16px rgba(79, 70, 229, 0.35), 0 2px 6px rgba(49, 46, 129, 0.08);
}

.r360-console--open .r360-console__nav {
    border-color: transparent;
    background-image:
        linear-gradient(var(--r360-surface), var(--r360-surface)),
        linear-gradient(100deg, rgba(99, 102, 241, 0.55), rgba(236, 72, 153, 0.45) 50%, rgba(6, 182, 212, 0.5));
    background-origin: border-box;
    background-clip: padding-box, border-box;
}

/* Resting console icons carry a whisper of their module, so the strip reads as eight families
   rather than twenty grey glyphs — a 45% blend with the muted ink, so they stay above 3:1. */
.r360-console:not(.r360-console--open) .mud-navmenu.mud-navmenu-default .mud-nav-link:not(.active) .mud-nav-link-icon {
    color: color-mix(in srgb, var(--r360-mod-ink) 45%, var(--r360-ink-muted));
}

.r360-console .mud-navmenu.mud-navmenu-default .mud-nav-link:hover:not(.active) .mud-nav-link-icon {
    color: var(--r360-mod-ink);
    transform: translateY(-1px);
}

.r360-console .mud-navmenu.mud-navmenu-default .mud-nav-link .mud-nav-link-icon {
    transition: transform var(--r360-speed-base) var(--r360-ease), color var(--r360-speed-fast) var(--r360-ease);
}

/* The brand island: the mark in the brand gradient, the wordmark stays solid ink — app-title is
   measured by the contrast walker, and gradient TEXT (background-clip:text) reads as transparent. */
.r360-brand-mark {
    filter: drop-shadow(0 4px 8px rgba(124, 58, 237, 0.35));
}

/* The branch code chip takes the brand gradient. White on #4F46E5/#7C3AED clears 5.7:1. */
.r360-branch__code:not(.r360-branch__code--menu) {
    background-color: var(--r360-cta);
    background-image: var(--r360-brand-gradient);
    color: #FFFFFF;
}

/* The Counter Bar (Ctrl+K) lifts a violet glow on hover. */
.mud-button-root.r360-counterbar:hover {
    border-color: color-mix(in srgb, #7C3AED 35%, var(--r360-hairline));
    box-shadow: 0 10px 24px -12px rgba(124, 58, 237, 0.45);
}

/* ── Aurora — page furniture ─────────────────────────────────────────────────────────────────── */

/* The page title gets a short bar of its module's gradient above it: the one place on a worklist
   screen where the module announces itself, without putting colour under any words. */
.r360-page-header::before,
.r360-intro::before {
    content: "";
    display: block;
    width: 44px;
    height: 5px;
    margin-bottom: var(--r360-space-3);
    border-radius: var(--r360-radius-pill);
    background-color: var(--r360-mod-c);
    background-image: var(--r360-mod-bright);
    box-shadow: 0 4px 12px -2px var(--r360-mod-glow);
}

/* Panels and figure tiles lift on hover — they are what a page is made of. */
.r360-stat-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 16px 30px -16px var(--r360-mod-glow);
}

/* Focus: the ring takes the module's hue. Still an outline/box-shadow on the element itself, which
   is what ShellAccessibilityTests requires of a focused control. */
.r360-stage .mud-input.mud-input-outlined:focus-within {
    box-shadow: 0 0 0 3px var(--r360-mod-ring);
}

/* A chip carrying Color.Primary is a SELECTION marker (a filter chip), never a status — status
   chips use success/warning/error and keep their own colours. */
.mud-chip.mud-chip-filled.mud-chip-color-primary {
    background-color: var(--r360-mod-a);
    background-image: var(--r360-mod-fill);
    color: #FFFFFF;
}

.mud-chip.mud-chip-outlined.mud-chip-color-primary,
.mud-chip.mud-chip-text.mud-chip-color-primary {
    background-color: var(--r360-mod-soft);
    border-color: color-mix(in srgb, var(--r360-mod-c) 45%, transparent);
    color: var(--r360-mod-ink);
}

/* Progress and switches follow the module rather than the fixed accent. */
.r360-stage .mud-progress-linear-bar.mud-primary {
    background-image: var(--r360-mod-bright);
}

@media (prefers-reduced-motion: reduce) {
    .r360-stat-card:hover,
    .r360-console .mud-navmenu.mud-navmenu-default .mud-nav-link:hover:not(.active) .mud-nav-link-icon {
        transform: none;
    }
}

/* ── Purchasing, suppliers and store requisitions (2026-09-26) ─────────────────────────────────
   Global rather than scoped: every one of these lands on a component root or inside a MudBlazor
   component, where a scoped ::deep has no ancestor to descend from (docs/ui-conventions.md §2). */

/* A form laid out as fields that wrap: two to four across on a wide screen, one on a phone. */
.r360-form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: 0.75rem 1rem;
    align-items: start;
}

.r360-form-grid--wide { grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); }

/* The supplier page: details beside the status and commitment card, stacked below 1100px. */
.r360-supplier-grid {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 1rem;
    align-items: start;
    margin-bottom: 1rem;
}

@media (max-width: 1100px) {
    .r360-supplier-grid { grid-template-columns: minmax(0, 1fr); }
}

.r360-muted {
    color: var(--r360-ink-muted);
    font-size: 0.8125rem;
}

.r360-row-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
}

/* One purchase-order line being written: the part takes the room, quantity and cost stay narrow. */
.r360-po-entry {
    display: grid;
    grid-template-columns: minmax(16rem, 3fr) minmax(7rem, 1fr) minmax(8rem, 1fr) auto;
    gap: 0.75rem;
    align-items: start;
}

.r360-po-entry .r360-po-entry__actions {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    padding-top: 0.5rem;
}

@media (max-width: 900px) {
    .r360-po-entry { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .r360-po-entry .r360-po-entry__part { grid-column: 1 / -1; }
}

/* The receiving line a scan just counted. Stated at MudSimpleTable's own cell specificity plus one,
   or its cell rule wins silently (the Kaunta log's six-table defect). */
.mud-simple-table table tbody tr.r360-row--hit > td {
    background-color: var(--r360-accent-soft);
    transition: background-color 400ms ease;
}

/* ── Print ───────────────────────────────────────────────────────────────────────────────────────
   The shell is chrome, and chrome does not belong on paper. The receipt and quotation documents
   are styled by document.css; this only removes the console and the islands from any printed page
   and unbounds a support article. */
@media print {
    .r360-topline,
    .r360-console,
    .r360-console-scrim,
    .sup-noprint,
    .sup-search { display: none !important; }

    .r360-stage { padding: 0; max-width: none; }
    .sup-body { max-width: none; }
    .sup-card, .sup-command__text, .sup-callout { break-inside: avoid; }
}


/* ── Online orders (2026-09-26) ────────────────────────────────────────────────────────────────
   Customer care's board, an order, the rider's screen, the M-Pesa ledger. All HTML these pages
   write themselves, so it could be scoped — it lives here because the tabs strip is a component
   and the board's lanes are read by several pages, and one place is easier to keep consistent. */

.oo-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--r360-space-2);
    margin-bottom: var(--r360-space-4);
}

.oo-tabs__link {
    padding: 6px 14px;
    border-radius: var(--r360-radius-pill);
    border: 1px solid var(--r360-hairline);
    color: var(--r360-ink);
    text-decoration: none;
    background: var(--r360-surface);
    font-weight: 600;
    font-size: 0.875rem;
}

.oo-tabs__link:hover { border-color: var(--r360-mod-ink); }

.oo-tabs__link--active {
    background: var(--r360-mod-fill, var(--r360-mod-a));
    border-color: transparent;
    color: #FFFFFF;
}

.oo-board {
    display: grid;
    grid-template-columns: repeat(5, minmax(220px, 1fr));
    gap: var(--r360-space-3);
    align-items: start;
    overflow-x: auto;
    padding-bottom: var(--r360-space-3);
}

@media (max-width: 1100px) {
    .oo-board { grid-template-columns: repeat(5, 260px); }
}

.oo-lane {
    background: var(--r360-surface-2);
    border: 1px solid var(--r360-hairline);
    border-radius: var(--r360-radius-panel);
    padding: var(--r360-space-3);
    display: flex;
    flex-direction: column;
    gap: var(--r360-space-2);
    min-height: 160px;
}

.oo-lane__head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-weight: 700;
    color: var(--r360-mod-ink);
}

.oo-lane__count {
    min-width: 1.75rem;
    text-align: center;
    border-radius: var(--r360-radius-pill);
    background: var(--r360-surface);
    border: 1px solid var(--r360-hairline);
    padding: 0 6px;
}

.oo-card {
    background: var(--r360-surface);
    border: 1px solid var(--r360-hairline);
    border-radius: var(--r360-radius-control);
    padding: var(--r360-space-3);
    display: flex;
    flex-direction: column;
    gap: 6px;
    box-shadow: var(--r360-shadow-1);
}

.oo-card--late { border-inline-start: 3px solid var(--r360-failure); }

.oo-card__top {
    display: flex;
    justify-content: space-between;
    gap: var(--r360-space-2);
    font-weight: 700;
}

.oo-card__ref { color: var(--r360-mod-ink); text-decoration: none; }
.oo-card__ref:hover { text-decoration: underline; }

.oo-card__who { color: var(--r360-ink-muted); font-size: 0.875rem; }

.oo-card__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    font-size: 0.8125rem;
    color: var(--r360-ink-muted);
}

.oo-card__assign {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 6px;
    align-items: center;
}

.oo-detail {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: var(--r360-space-4);
}

.oo-facts { display: grid; gap: 6px; margin-bottom: var(--r360-space-2); }

.oo-facts > div {
    display: grid;
    grid-template-columns: 9.5rem 1fr;
    gap: var(--r360-space-2);
}

.oo-facts > div > span:first-child { color: var(--r360-ink-muted); }

.oo-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--r360-space-2);
    align-items: center;
}

.oo-timeline {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--r360-space-2);
}

.oo-timeline li {
    display: grid;
    grid-template-columns: 11rem 1fr auto;
    gap: var(--r360-space-3);
    padding-block: 6px;
    border-bottom: 1px solid var(--r360-hairline);
}

.oo-timeline__when { color: var(--r360-ink-muted); font-family: var(--r360-font-mono); font-size: 0.8125rem; }
.oo-timeline__who { color: var(--r360-ink-muted); font-size: 0.8125rem; }

.oo-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: var(--r360-space-3);
    margin-bottom: var(--r360-space-4);
}

.oo-pipeline { display: flex; flex-wrap: wrap; gap: var(--r360-space-3); }

.oo-pipeline__step {
    display: flex;
    flex-direction: column;
    min-width: 8rem;
    padding: var(--r360-space-3);
    border: 1px solid var(--r360-hairline);
    border-radius: var(--r360-radius-control);
}

.oo-pipeline__count { font-size: 1.75rem; font-weight: 800; color: var(--r360-mod-ink); text-align: start; }

/* The signature pad: the page must not scroll under a finger that is signing. */
.oo-signature {
    display: block;
    width: 100%;
    max-width: 520px;
    height: 180px;
    border: 1px dashed var(--r360-hairline-strong);
    border-radius: var(--r360-radius-control);
    background: #FFFFFF;
    touch-action: none;
    margin-block: var(--r360-space-2);
}

/* The till's M-Pesa prompt, under an M-Pesa tender row. */
.till-mpesa {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--r360-space-2);
    align-items: center;
    margin: calc(-1 * var(--r360-space-2)) 0 var(--r360-space-3);
}

.till-mpesa__state {
    grid-column: 1 / -1;
    font-size: 0.8125rem;
    color: var(--r360-ink-muted);
}

.till-mpesa__state--paid { color: var(--r360-confirmed-text, var(--r360-confirmed)); font-weight: 700; }

/* Delivery — the paid step stacks: receipt, "ask the customer to sign", the pad, then the buttons.
   It sits in the action row's flex container, so it claims the whole row. */
.oo-sign {
    display: grid;
    gap: var(--r360-space-2);
    flex: 1 1 100%;
    justify-items: start;
}

.oo-sign .mud-alert { width: 100%; }

/* Delivery — what the rider finished in the last day. The order they have just marked delivered
   arrives tinted, so the move from "to deliver" to "done" is something they can see happen. */
.dlv-finished { display: grid; gap: 2px; }

.dlv-finished__row {
    display: grid;
    grid-template-columns: auto auto 1fr auto;
    gap: var(--r360-space-1) var(--r360-space-2);
    align-items: center;
    padding: var(--r360-space-2);
    border-bottom: 1px solid var(--r360-hairline);
    border-radius: var(--r360-radius-control);
}

.dlv-finished__row:last-child { border-bottom: 0; }

.dlv-finished__state { grid-column: 2 / 4; font-size: 0.8125rem; color: var(--r360-ink-muted); }

.dlv-finished__row > .r360-money { grid-row: 1; grid-column: 4; }

.dlv-finished__row--new { background: var(--r360-confirmed-bg); animation: dlv-arrive 900ms ease-out; }

@keyframes dlv-arrive {
    from { background: color-mix(in srgb, var(--mud-palette-success) 35%, var(--mud-palette-surface)); }
}

@media (prefers-reduced-motion: reduce) {
    .dlv-finished__row--new { animation: none; }
}

/* A money figure in a facts list reads beside its label like every other fact, not flushed to the
   far edge of the card where the eye loses which row it belongs to. */
.oo-facts > div > .r360-money { text-align: start; }

/* An order number is 24 characters of mono (branch · device · sequence) and a lane is about 220px
   wide, so it cannot share a line with the total. It keeps its own line whole — broken at the
   hyphens it read as three different numbers — and the total drops beneath it. */
.oo-card__top { flex-wrap: wrap; row-gap: 2px; }
.oo-card__ref { white-space: nowrap; font-size: 0.8125rem; }
.oo-card__top > :last-child { white-space: nowrap; margin-inline-start: auto; }

/* The rider picker and its button stack in a lane; side by side the select was a sliver. */
.oo-card__assign { grid-template-columns: 1fr; }

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   Reporting — chart tones (FR-RPT-01…06, 2026-09-29).

   One colour per MEANING, the same on every chart: the counter is always sunset orange, online is
   always teal, quotations are always violet. A channel that changed colour between the trend and
   the donut would make the owner re-read every legend. Status colours (green, amber, red) are not
   used for series, so a series never reads as good or bad news. Every chart states its figures in
   text as well, so colour is never the only carrier (NFR-UX-04).
   ═══════════════════════════════════════════════════════════════════════════════════════════ */
:root {
    --r360-series-counter: #EA580C;
    --r360-series-quote: #7C3AED;
    --r360-series-online: #0891B2;
    --r360-series-app: #0D9488;
    --r360-series-green: #16A34A;
    --r360-series-blue: #2563EB;
    --r360-series-amber: #D97706;
    --r360-series-pink: #DB2777;
    --r360-series-slate: #64748B;
}

:root[data-r360-theme="dark"] {
    --r360-series-counter: #FB923C;
    --r360-series-quote: #A78BFA;
    --r360-series-online: #22D3EE;
    --r360-series-app: #2DD4BF;
    --r360-series-green: #4ADE80;
    --r360-series-blue: #60A5FA;
    --r360-series-amber: #FBBF24;
    --r360-series-pink: #F472B6;
    --r360-series-slate: #94A3B8;
}

.r360-tone--counter { background: var(--r360-series-counter); }
.r360-tone--quote { background: var(--r360-series-quote); }
.r360-tone--online { background: var(--r360-series-online); }
.r360-tone--app { background: var(--r360-series-app); }
.r360-tone--green { background: var(--r360-series-green); }
.r360-tone--blue { background: var(--r360-series-blue); }
.r360-tone--amber { background: var(--r360-series-amber); }
.r360-tone--pink { background: var(--r360-series-pink); }
.r360-tone--slate { background: var(--r360-series-slate); }
.r360-tone--accent { background: var(--r360-mod-fill, var(--r360-primary)); }
.r360-tone--bad { background: var(--r360-failure); }

.r360-stroke--counter { stroke: var(--r360-series-counter); }
.r360-stroke--quote { stroke: var(--r360-series-quote); }
.r360-stroke--online { stroke: var(--r360-series-online); }
.r360-stroke--app { stroke: var(--r360-series-app); }
.r360-stroke--green { stroke: var(--r360-series-green); }
.r360-stroke--blue { stroke: var(--r360-series-blue); }
.r360-stroke--amber { stroke: var(--r360-series-amber); }
.r360-stroke--pink { stroke: var(--r360-series-pink); }
.r360-stroke--slate { stroke: var(--r360-series-slate); }

.r360-swatch {
    display: inline-block;
    flex: none;
    width: 10px;
    height: 10px;
    border-radius: 3px;
}

.r360-swatch--line {
    height: 2px;
    width: 14px;
    border-radius: 1px;
    background: var(--r360-ink);
}

.r360-swatch--projected {
    background: transparent;
    border: 1.5px dashed var(--r360-mod-c, var(--r360-primary));
}

/* Printing a report: the console, the islands, the filters and the tabs' chrome go; the figures stay.
   Charts keep their colours, because an owner printing a trend wants the trend. */
@media print {
    .r360-report-toolbar,
    .r360-console,
    .r360-topline,
    .no-print {
        display: none !important;
    }

    .r360-stage {
        padding: 0 !important;
    }

    .r360-report-card,
    .r360-kpi {
        break-inside: avoid;
        box-shadow: none !important;
    }

    * {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
}

/* ── Report pages: layout (2026-09-29) ───────────────────────────────────────────────────────
   Global rather than scoped because most of these classes land on SectionCard's root, a component,
   and scoped CSS never reaches a component root (docs/ui-conventions.md §2). Twelve columns,
   six below 1100px, one below 700px. */
.ana-grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--r360-space-4);
    margin-bottom: var(--r360-space-4);
    align-items: start;
}

.ana-grid > * { grid-column: span 12; min-width: 0; margin: 0 !important; }
.ana-grid > .ana-span-2 { grid-column: span 2; }
.ana-grid > .ana-span-3 { grid-column: span 3; }
.ana-grid > .ana-span-4 { grid-column: span 4; }
.ana-grid > .ana-span-6 { grid-column: span 6; }
.ana-grid > .ana-span-8 { grid-column: span 8; }
.ana-grid > .ana-span-12 { grid-column: span 12; }

/* KPI rows: tiles in a strip, the hero tile two tracks wide. */
.ana-grid--kpis {
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    align-items: stretch;
}

.ana-grid.ana-grid--kpis > * { grid-column: auto; }
.ana-grid.ana-grid--kpis > .ana-span-2 { grid-column: span 2; }
.ana-grid--kpis > .ana-span-2 > .r360-kpi,
.ana-grid--kpis > .r360-kpi { height: 100%; }

@media (max-width: 1100px) {
    .ana-grid > .ana-span-4,
    .ana-grid > .ana-span-6,
    .ana-grid > .ana-span-8 { grid-column: span 12; }
    .ana-grid > .ana-span-3 { grid-column: span 6; }
}

@media (max-width: 700px) {
    /* (0,3,0), so it beats the generic span-12 rule below at equal (0,2,0) — which, declared later,
       used to win and push the hero tile off a phone screen. */
    .ana-grid.ana-grid--kpis > .ana-span-2 { grid-column: span 1; }
    .ana-grid > .ana-span-2,
    .ana-grid > .ana-span-3 { grid-column: span 12; }
}

.ana-skeleton { border-radius: var(--r360-radius-panel) !important; }

/* Tabs: a segmented strip, one press per view. Buttons rather than MudTabs so each tab carries its
   own testid and reads as a plain control to a keyboard. */
.ana-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: var(--r360-space-4);
    padding: 4px;
    border-radius: var(--r360-radius-panel);
    background: var(--r360-canvas-inset);
    width: fit-content;
    max-width: 100%;
}

.ana-tab {
    appearance: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: 0;
    margin: 0;
    padding: 8px 14px;
    border-radius: calc(var(--r360-radius-panel) - 4px);
    background: transparent;
    color: var(--r360-ink-muted);
    font: inherit;
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
    transition: background var(--r360-speed-fast) var(--r360-ease), color var(--r360-speed-fast) var(--r360-ease);
}

.ana-tab:hover { color: var(--r360-ink); }
.ana-tab:focus-visible { outline: 2px solid var(--r360-primary); outline-offset: 1px; }

.ana-tab--on {
    background: var(--r360-surface);
    color: var(--r360-mod-ink, var(--r360-ink));
    box-shadow: var(--r360-shadow-1);
}

.ana-panel { min-width: 0; }

.ana-muted { margin: 0; color: var(--r360-ink-muted); font-size: 0.875rem; }
.ana-footnote { margin: var(--r360-space-3) 0 0; color: var(--r360-ink-muted); font-size: 0.8125rem; }
.ana-sentence { margin: 0 0 var(--r360-space-4); color: var(--r360-ink); line-height: 1.55; }

.ana-insights { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--r360-space-2); }

.ana-insight {
    display: grid;
    grid-template-columns: 20px 1fr;
    gap: var(--r360-space-2);
    align-items: start;
    padding: var(--r360-space-3);
    border-radius: var(--r360-radius-control);
    font-size: 0.875rem;
    line-height: 1.45;
    background: var(--r360-surface-2);
    color: var(--r360-ink);
}

.ana-insight--warning { background: var(--r360-failure-bg); }
.ana-insight--warning .mud-icon-root { color: var(--r360-failure-text); }
.ana-insight--watch { background: var(--r360-attention-bg); }
.ana-insight--watch .mud-icon-root { color: var(--r360-attention-text); }
.ana-insight--info .mud-icon-root { color: var(--r360-mod-ink, var(--r360-primary)); }

.ana-table-wrap { overflow-x: auto; }

.ana-desc {
    display: block;
    font-size: 0.8125rem;
    color: var(--r360-ink-muted);
    max-width: 34ch;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ana-abc {
    display: inline-grid;
    place-items: center;
    width: 26px;
    height: 22px;
    border-radius: 6px;
    font-weight: 800;
    font-size: 0.75rem;
}

.ana-abc--a { background: var(--r360-confirmed-bg); color: var(--r360-confirmed-text); }
.ana-abc--b { background: var(--r360-attention-bg); color: var(--r360-attention-text); }
.ana-abc--c { background: var(--r360-surface-2); color: var(--r360-ink-muted); }

.ana-cum {
    display: inline-block;
    vertical-align: middle;
    width: 64px;
    height: 6px;
    margin-inline-end: 8px;
    border-radius: 999px;
    background: var(--r360-surface-2);
    overflow: hidden;
}

.ana-cum > i { display: block; height: 100%; background: var(--r360-mod-fill, var(--r360-primary)); }
.ana-cum__text { font-variant-numeric: tabular-nums; font-size: 0.8125rem; color: var(--r360-ink-muted); }

.ana-total td { font-weight: 700; border-top: 2px solid var(--r360-hairline-strong); }

/* Channel cards: one per channel, the same facts on each, so they compare down and across. */
.ana-channel-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--r360-space-3);
}

.ana-channel {
    padding: var(--r360-space-4);
    border-radius: var(--r360-radius-control);
    border: 1px solid var(--r360-hairline);
    background: var(--r360-surface);
}

.ana-channel header { display: flex; align-items: center; gap: 8px; }
.ana-channel__share { margin-inline-start: auto; font-weight: 700; color: var(--r360-ink-muted); font-variant-numeric: tabular-nums; }

.ana-channel__value {
    margin: 6px 0 10px;
    font-family: var(--r360-font-display);
    font-size: 1.35rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.ana-channel dl { margin: 0; display: grid; gap: 4px; }
.ana-channel dl > div { display: flex; justify-content: space-between; gap: 8px; font-size: 0.8125rem; }
.ana-channel dt { color: var(--r360-ink-muted); }
.ana-channel dd { margin: 0; font-variant-numeric: tabular-nums; font-family: var(--r360-font-mono); }

/* Pipeline: one tile per open status, the count large. The delivery desk's "right now". */
.ana-pipeline {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: var(--r360-space-3);
}

.ana-stage {
    position: relative;
    padding: var(--r360-space-3) var(--r360-space-4);
    border-radius: var(--r360-radius-control);
    background: var(--r360-surface-2);
    border: 1px solid var(--r360-hairline);
}

.ana-stage strong {
    display: block;
    font-family: var(--r360-font-display);
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.ana-stage span { font-size: 0.8125rem; color: var(--r360-ink-muted); }
.ana-stage--alert { background: var(--r360-failure-bg); border-color: transparent; }
.ana-stage--alert strong { color: var(--r360-failure-text); }

/* Where the time goes: the four legs of a delivery, laid end to end in proportion. */
.ana-legs { display: grid; gap: var(--r360-space-3); }
.ana-legs__bar { display: flex; height: 14px; border-radius: 999px; overflow: hidden; background: var(--r360-surface-2); }
.ana-legs__bar > span { display: block; height: 100%; }
.ana-legs__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.ana-legs__list li { display: grid; grid-template-columns: 12px 1fr auto; gap: 8px; align-items: center; font-size: 0.875rem; }
.ana-legs__list b { font-variant-numeric: tabular-nums; font-family: var(--r360-font-mono); font-weight: 500; }

.ana-chip {
    display: inline-flex;
    align-items: center;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 700;
    white-space: nowrap;
}

.ana-chip--bad { background: var(--r360-failure-bg); color: var(--r360-failure-text); }
.ana-chip--good { background: var(--r360-confirmed-bg); color: var(--r360-confirmed-text); }
.ana-chip--neutral { background: var(--r360-surface-2); color: var(--r360-ink-muted); }

.ana-quote {
    margin: 0;
    padding: var(--r360-space-3);
    border-inline-start: 3px solid var(--r360-failure);
    border-radius: 0 var(--r360-radius-control) var(--r360-radius-control) 0;
    background: var(--r360-surface-2);
    font-size: 0.875rem;
}

.ana-quote footer { margin-top: 4px; font-size: 0.75rem; color: var(--r360-ink-muted); }
.ana-quotes { display: grid; gap: var(--r360-space-2); margin-top: var(--r360-space-3); }

/* A printed shift report: a receipt-width column. */
.ana-shift-doc { max-width: 560px; }
.ana-shift-doc dl { margin: 0; display: grid; gap: 6px; }
.ana-shift-doc dl > div { display: flex; justify-content: space-between; gap: 12px; }
.ana-shift-doc dt { color: var(--r360-ink-muted); }
.ana-shift-doc dd { margin: 0; font-family: var(--r360-font-mono); font-variant-numeric: tabular-nums; }
.ana-shift-doc .ana-shift-doc__key dd { font-weight: 700; font-size: 1.1rem; }

.ana-shift-kind {
    display: inline-block;
    margin-bottom: var(--r360-space-3);
    padding: 4px 12px;
    border-radius: 999px;
    font-weight: 800;
    letter-spacing: 0.03em;
    background: var(--r360-mod-soft, var(--r360-accent-soft));
    color: var(--r360-mod-ink, var(--r360-ink));
}

.ana-subhead { margin: var(--r360-space-4) 0 0; font-size: 0.875rem; font-weight: 700; color: var(--r360-ink); }

.ana-stack { display: grid; gap: var(--r360-space-4); }

/* A pipeline stage on the dashboard is a link to the order board. */
a.ana-stage { color: var(--r360-ink); text-decoration: none; transition: border-color var(--r360-speed-fast) var(--r360-ease); }
a.ana-stage:hover, a.ana-stage:focus-visible { border-color: var(--r360-mod-c, var(--r360-primary)); }
