/* rently-nav.css — Initiative C · C2 Pt3.B (global chrome nav styles)
   Pt3.A extracted these rules VERBATIM from the MainNav.razor + SearchNav.razor inline
   style blocks (behavior-preserving no-op; source order MainNav then SearchNav).
   Pt3.B (this pass): tokenized the brand hex to palette vars (teal -> --rently-primary,
   text-teal -> --rently-primary-dark, teal rgba -> --rently-primary-rgb; red ->
   --rently-secondary, red rgba -> --rently-secondary-rgb); DE-COLLIDED the two merged
   duplicates by renaming (keyframes pulse -> main-nav-pulse / search-nav-pulse;
   .animate-in -> .main-nav-animate-in / .search-animate-in, with both components' markup
   updated); removed 3 inert ::deep rules; bumped the search-chip touch target to 44px.
   A few near-miss reds and the search-pill category colours stay raw, tagged for C4's
   semantic-palette engine. Pt3.C restructures + scopes per section-reactivity. */

/* ===================== MainNav (was MainNav.razor inline style, lines 682-1494) ===================== */
    /* Z-index Architecture
       MudBlazor's PopoverProvider auto-assigns z-indices (~1400+) to overlays/popovers.
       MainNav must be ABOVE these so Browse Rentables remains interactive when search overlay is open. */
    :root {
        --z-nav-behind-drawer: 1050;
        --z-drawer-backdrop: 1300;
        --z-drawer: 1350;
        --z-drawer-overlay: 1400;
        --z-category-overlay: 1450;  /* category mega-menu scrim (was CategoryNav-local — N1 2026-07-24) */
        --z-nav-normal: 1500;
        --z-category-popover: 1500;  /* category mega-menu panel (teleported; later DOM order wins the tie) */
        --z-notifications: 1600;
        /* Height of the desktop main nav bar (64px toolbar + 2×5px padding + surface border).
           The category scrim + welded mega-popover start at this offset so the bar is never
           dimmed. QA-measured live 2026-07-24: 75px on the tinted-glass surface (1px border). */
        --rently-mainnav-height: 75px;
    }

    /* The hairline surface's border-bottom is 2px (vs tinted-glass 1px) — keep the weld seam exact. */
    html[data-nav-surface="hairline"] {
        --rently-mainnav-height: 76px;
    }

    /* ══ Shared nav-popover recipe — G4 (2026-07-22) ═════════════════════════════════════════════════
       The four surfaces the nav opens (rentables suggestions, address panel, account menu, category
       mega-menu) were each styled independently and had drifted apart — different radii (4px vs 8px),
       different elevations, some bordered and some not. These give them one vocabulary.

       GEOMETRY ONLY, deliberately. Accent-derived values (hover washes, heading ink) are NOT tokenised
       here: a custom property's var()s are substituted at the element that DECLARES it, so anything
       referencing --section-accent from :root would resolve against the storefront fallback rather than
       the live section. Worse, these popovers are portalled into MudPopoverProvider at the document
       root, which is OUTSIDE the section shell that carries --section-accent — so accent lookups must
       stay in the individual rules, where the brand-teal fallback is the correct and intended result. */
    :root {
        --rently-popover-radius: var(--rently-radius-md, 8px);
        --rently-popover-shadow: 0 8px 24px -4px rgba(0, 0, 0, 0.12);
        --rently-popover-pad: 8px;
        --rently-popover-heading-size: 0.68rem;
    }

    /* Dynamic MainNav z-index */
    .main-nav-appbar {
        /* Initiative C · C2 Pt3.C — Tinted Glass surface: a translucent accent wash + blur, the accent only
           as a touch. The accent hairline is the internal divider above the search bar (Blend-gradient seam
           keeps it here, not on the search bar). Falls back to brand teal on the storefront (no --section-accent). */
        background: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 10%, rgba(255, 255, 255, 0.80));
        -webkit-backdrop-filter: blur(12px);
        backdrop-filter: blur(12px);
        border-bottom: 1px solid color-mix(in srgb, var(--section-accent, var(--rently-primary)) 60%, transparent);
        z-index: var(--z-nav-normal);
        padding-top: 5px !important;
        padding-bottom: 5px !important;
        will-change: transform;
        transition: z-index 0.2s ease;
    }

    .main-nav-appbar.nav-behind-drawer {
        z-index: var(--z-nav-behind-drawer);
    }

    /* N1 (2026-07-24): while the category mega-menu is open, release the appbar's will-change
       containment. will-change:transform makes the bar the CONTAINING BLOCK for fixed descendants,
       and the category scrim (a MudOverlay rendered INSIDE the bar — see CategoryNav.razor) was
       being pinned to the bar's own box: it darkened the nav itself and never dimmed the page.
       With containment released, the fixed scrim spans the viewport again; its own top offset
       (--rently-mainnav-height) starts it BELOW the bar, so no part of the top nav is ever
       covered — no z-index raises (and no drawer/search-overlay regressions) needed anywhere. */
    .main-nav-appbar:has(.browse-rentables-btn.popover-open) {
        will-change: auto;
    }

    .mobile-nav-appbar {
        /* Initiative C · C2 Pt3.C — Tinted Glass surface (mobile main bar). */
        background: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 10%, rgba(255, 255, 255, 0.80));
        -webkit-backdrop-filter: blur(12px);
        backdrop-filter: blur(12px);
        border-bottom: 1px solid color-mix(in srgb, var(--section-accent, var(--rently-primary)) 60%, transparent);
        z-index: var(--z-nav-normal);
        padding: 8px 16px !important;
        transition: z-index 0.2s ease;
    }

    .mobile-nav-appbar.nav-behind-drawer {
        z-index: var(--z-nav-behind-drawer);
    }

    /* S8-04 — the three section sidebar drawers (Account / Franchise / SA) are CSS-checkbox drawers owned
       by STATIC layouts, so they cannot reach MainNav's .nav-behind-drawer channel (that class is toggled
       from MainNav's own circuit). While any of them is open, demote the nav exactly as MainNav demotes
       itself for its own drawers: the drawers sit at z-1300 with a z-1290 backdrop, and the nav's normal
       1500 painted straight over their headers whenever page scroll was less than the nav height.
       :has() is already load-bearing in this sheet (the will-change release above) and in the rail-grid
       collapse; without it the behaviour degrades to today's nav-over-drawer — no new failure mode. */
    /* S9-01 re-review fix: MEDIA-SCOPED per family, matching each layout's own drawer breakpoint
       (Account 959.98 / Franchise 1199 / SA 959.98). Unscoped, a checkbox left checked at mobile kept
       the body scroll frozen and the nav demoted after a resize/rotation past the breakpoint, where
       the drawer UI itself no longer exists to uncheck it. */
    @media (max-width: 959.98px) {
        body:has(.account-sidebar-checkbox:checked) .main-nav-appbar,
        body:has(.account-sidebar-checkbox:checked) .mobile-nav-appbar,
        body:has(.sa-sidebar-checkbox:checked) .main-nav-appbar,
        body:has(.sa-sidebar-checkbox:checked) .mobile-nav-appbar {
            z-index: var(--z-nav-behind-drawer);
        }
    }

    @media (max-width: 1199px) {
        body:has(.org-sidebar-checkbox:checked) .main-nav-appbar,
        body:has(.org-sidebar-checkbox:checked) .mobile-nav-appbar {
            z-index: var(--z-nav-behind-drawer);
        }
    }

    /* Modal scroll lock for the same three. MainNav's own drawers lock via body.drawer-open (below);
       these have no circuit to add a class from, so the lock is derived from the checkbox state.
       overflow only — NOT the position:fixed treatment body.drawer-open uses: these drawers are opened
       by an in-flow toggle partway down the page, and taking the body out of flow would scroll-jump it
       to the top behind the panel. Same per-family media scoping as the demotion above. */
    @media (max-width: 959.98px) {
        body:has(.account-sidebar-checkbox:checked),
        body:has(.sa-sidebar-checkbox:checked) {
            overflow: hidden;
        }
    }

    @media (max-width: 1199px) {
        body:has(.org-sidebar-checkbox:checked) {
            overflow: hidden;
        }
    }

    /* ════════════════════════════════════════════════════════════════════════════════════════════════
       Initiative C · C2 Pt3.C-ii — NavSurface "Hairline" (the LIVE DEFAULT; admins switch to "TintedGlass"
       on Site Branding → SiteConfig.NavSurface → data-nav-surface on <html>). A crisp WHITE chrome with a
       section-accent hairline, replacing the frosted Tinted-Glass wash above. These are attribute-scoped
       OVERRIDES only — the Tinted-Glass base rules stay untouched as the "tintedglass" fallback. The
       responsive bars switch via MudHidden server-render, so a single global block overrides every breakpoint
       (higher specificity than the bare `.x` base rules). var(--section-accent) still resolves at the appbar
       (a descendant of the section layout root that carries it), so the hairline stays section-reactive —
       NEVER declare these as :root tokens (--section-accent is unset on :root → would compute invalid).
       The hairline uses --section-accent-text strength: it clears WCAG 1.4.11 (≥3:1 non-text) on white AND
       frost, whereas the raw accent is ~3.09:1 and dips below 3:1 over tinted page surfaces. Storefront has no
       --section-accent → both the surface (white) and the hairline (teal --rently-primary-dark) stay neutral. */
    [data-nav-surface="hairline"] .main-nav-appbar,
    [data-nav-surface="hairline"] .mobile-nav-appbar {
        background: var(--rently-card-bg);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        border-bottom: 2px solid var(--section-accent-text, var(--rently-primary-dark));
    }

    /* ════════════════════════════════════════════════════════════════════════════════════════════════
       Initiative C · C2 Pt3.C-ii (search split) — the SEARCH bar's surface is now keyed off its OWN attribute,
       data-search-nav-surface (SiteConfig.SearchNavSurface), so the top nav and the search bar can be set to
       different surfaces (e.g. Tinted Glass top + Solid search). These hairline overrides previously rode on
       data-nav-surface together with the top bar; they were RE-KEYED to data-search-nav-surface so the two
       navs decouple. The Tinted-Glass base search rules (.search-nav-appbar etc.) stay unqualified as the
       shared "tintedglass" fallback. */
    [data-search-nav-surface="hairline"] .search-nav-appbar,
    [data-search-nav-surface="hairline"] .tablet-search-bar,
    [data-search-nav-surface="hairline"] .mobile-search-bar {
        background: var(--rently-card-bg);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        border-bottom: 1px solid var(--rently-border);
    }

    /* Search FIELDS would vanish white-on-white on the now-white bar — tint to the subtle surface so they
       read as raised; their existing box-shadow keeps the elevation/boundary. */
    [data-search-nav-surface="hairline"] .search-bar-stack,
    [data-search-nav-surface="hairline"] .tablet-search-field,
    [data-search-nav-surface="hairline"] .mobile-search-field {
        background-color: var(--rently-subtle-bg);
    }

    /* ════════════════════════════════════════════════════════════════════════════════════════════════
       Initiative C · C2 Pt3.C-ii — NavSurface "Solid" (the THIRD option, alongside Hairline + Tinted Glass).
       A FLAT darkened-accent fill with WHITE foreground — no blur, no translucency — replicating the Top Nav
       Lab's solid chrome finish (see TopNavExample.razor.css `[data-chrome-finish="solid"]`). The top bar is
       keyed off data-nav-surface, the search bar off data-search-nav-surface, so each can be Solid independently.

       SURFACE FILL — color-mix(in srgb, <accent> 70%, #0f172a):
         The 70% (not a higher mix) is the WCAG-VALIDATED ceiling: it is the strongest accent presence at which
         pure WHITE small text still clears SC 1.4.3 (4.5:1) on the WORST section accent (Account teal #35a0ae →
         #287683 = 4.55:1; Store red #D43C2C and Franchise are higher). Storefront has no --section-accent, so it
         falls back to --rently-primary (brand teal) → the same worst case, still ≥4.5:1. DO NOT raise the mix:
         a darker accent presence (e.g. 88%) drops white below 4.5:1 on the teal. This mirrors the lab's locked
         --chrome-surface literal exactly. The fill is already dark enough that it needs NO separate dark-mode
         variant — white text passes at 70% mix in both themes (the page behind it differs, the BAR does not).
         backdrop-filter is forced off (the surface is opaque; a blur would be wasted GPU work + a faint seam). */
    [data-nav-surface="solid"] .main-nav-appbar,
    [data-nav-surface="solid"] .mobile-nav-appbar {
        background: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 70%, #0f172a);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        border-bottom: 1px solid color-mix(in srgb, #000 18%, transparent);
    }

    [data-search-nav-surface="solid"] .search-nav-appbar,
    [data-search-nav-surface="solid"] .tablet-search-bar,
    [data-search-nav-surface="solid"] .mobile-search-bar {
        background: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 70%, #0f172a);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        border-bottom: 1px solid color-mix(in srgb, #000 18%, transparent);
    }

    /* ── FOREGROUND CONTRAST (the part that actually makes Solid a11y-safe) ──────────────────────────────
       On a dark accent bar the nav's normally-DARK text/links/icons/dividers would fail SC 1.4.3 (4.5:1 text)
       and 1.4.11 (3:1 UI). Force EVERYTHING on the bar to --rently-text-on-accent (white) so it clears both
       criteria over the 70%-mix fill (white-on-#287683 = 4.55:1 worst case, the same proof as the surface).
       The broad `.mud-typography / .mud-icon-root / .mud-button-label` catch-alls cover the MudBlazor-rendered
       links, labels and icons that otherwise inherit .mud-primary-text / .mud-secondary-text (brand teal/red,
       which fail on this fill); the named-class rules cover the elements that set colour via inline CSS vars
       (.help-link, .logout-button, .dropdown-arrow-icon, .nav-divider) — inline styles need !important to beat.
       Scoped to the appbar containers so NOTHING inside the drawers / popovers / dropdowns (which overlay on
       their own light surfaces) is touched. Hover/focus states keep white (a translucent-white wash carries the
       affordance instead of a colour shift).

       S11-01 — the `.logout-button` member of this list is DEAD but deliberately RETAINED. S8-06 moved Logout
       out of the app bar and into the account popover, which MudPopover portals to the provider island, so
       `.main-nav-appbar .logout-button` no longer has a match anywhere in the document. It is kept rather than
       deleted because the rest of this selector list is live and every entry shares one blast radius; removing
       one line here is a separate change with its own verification. It must NOT be re-pointed at the popover:
       that surface is a LIGHT card, and whitening the ink there is a live contrast failure, not a fix. */
    [data-nav-surface="solid"] .main-nav-appbar .mud-typography,
    [data-nav-surface="solid"] .main-nav-appbar .mud-button-label,
    [data-nav-surface="solid"] .main-nav-appbar .mud-icon-root,
    [data-nav-surface="solid"] .main-nav-appbar .mud-icon-button,
    [data-nav-surface="solid"] .main-nav-appbar .nav-divider,
    [data-nav-surface="solid"] .main-nav-appbar .help-link,
    [data-nav-surface="solid"] .main-nav-appbar .logout-button,
    [data-nav-surface="solid"] .main-nav-appbar .dropdown-arrow-icon,
    [data-nav-surface="solid"] .mobile-nav-appbar .mud-typography,
    [data-nav-surface="solid"] .mobile-nav-appbar .mud-button-label,
    [data-nav-surface="solid"] .mobile-nav-appbar .mud-icon-root,
    [data-nav-surface="solid"] .mobile-nav-appbar .mud-icon-button {
        color: var(--rently-text-on-accent) !important;
    }

    /* Help link hover normally shifts to the accent-text colour (dark) — keep it white on the solid bar. */
    [data-nav-surface="solid"] .main-nav-appbar .help-link:hover {
        color: var(--rently-text-on-accent) !important;
    }

    /* G4 — the divider is a 1px background: currentColor rule, so the white-flip above makes it FULLY
       opaque white, which is harsher than the pipe glyph ever was. Dial it to the mock's 30% edge. */
    [data-nav-surface="solid"] .main-nav-appbar .nav-divider {
        background: rgba(255, 255, 255, 0.30);
    }

    /* The mobile user card carries a faint section-accent border tuned for the WHITE hairline bar;
       on the dark solid fill swap to a translucent-white edge so it still reads as raised. (The
       desktop .user-card border was retired with the G3 mock cluster.) */
    [data-nav-surface="solid"] .mobile-nav-appbar .mobile-user-card {
        border-color: rgba(255, 255, 255, 0.28);
    }

    /* G3 avatar ring on the solid bar: translucent-white ground (mock recipe). */
    [data-nav-surface="solid"] .main-nav-appbar .user-avatar-ring {
        background: rgba(255, 255, 255, 0.20);
    }

    /* G4 — the account card's hover/open chip is an accent-12% wash, which is invisible on a bar that
       is ALREADY the accent. Swap to the translucent-white the mock uses for every raised state on the
       solid finish (same value as the Browse pill's solid override in CategoryNav). */
    [data-nav-surface="solid"] .main-nav-appbar .user-menu-container:hover .user-card,
    [data-nav-surface="solid"] .main-nav-appbar .user-card[aria-expanded="true"] {
        background-color: rgba(255, 255, 255, 0.18);
    }

    /* G4 — Logout's new hover reveals brand red, which is unreadable on the dark solid fill (and the
       whole bar is already force-whitened by the catch-all above). Keep it white and let a
       translucent-white wash carry the affordance, exactly as .help-link:hover does.
       Specificity note: the base .logout-button:hover rule is (0,3,0)!important and sits LATER in the
       file, so it would win a tie — these selectors are (0,4,0) to beat it outright.

       S11-01 — DEAD but deliberately RETAINED, same reasoning as the catch-all block above: Logout lives in
       the portalled account popover now, so `.main-nav-appbar .logout-button` matches nothing. Kept so the
       app-bar treatment is still on record if the button ever returns to the bar; NOT extended to the
       popover, where a white ink on a light card would be unreadable. */
    [data-nav-surface="solid"] .main-nav-appbar .logout-button:hover:not(:disabled),
    [data-nav-surface="solid"] .main-nav-appbar .logout-button:focus-visible:not(:disabled) {
        color: var(--rently-text-on-accent) !important;
        background-color: rgba(255, 255, 255, 0.14);
    }

    /* ── SEARCH-nav foreground (mirrors the top-nav block, keyed off data-search-nav-surface) ─────────────
       The search bar carries an input FIELD plus icons, dividers and the tablet/mobile placeholder LABELS. */
    [data-search-nav-surface="solid"] .search-nav-appbar .mud-typography,
    [data-search-nav-surface="solid"] .search-nav-appbar .mud-button-label,
    [data-search-nav-surface="solid"] .search-nav-appbar .mud-icon-root,
    [data-search-nav-surface="solid"] .search-nav-appbar .mud-icon-button,
    [data-search-nav-surface="solid"] .search-nav-appbar .search-icon,
    [data-search-nav-surface="solid"] .search-nav-appbar .search-divider,
    [data-search-nav-surface="solid"] .tablet-search-bar .mud-typography,
    [data-search-nav-surface="solid"] .tablet-search-bar .mud-icon-root,
    [data-search-nav-surface="solid"] .tablet-search-bar .tablet-search-label,
    [data-search-nav-surface="solid"] .tablet-search-bar .search-icon,
    [data-search-nav-surface="solid"] .mobile-search-bar .mud-typography,
    [data-search-nav-surface="solid"] .mobile-search-bar .mud-icon-root,
    [data-search-nav-surface="solid"] .mobile-search-bar .mobile-search-label,
    [data-search-nav-surface="solid"] .mobile-search-bar .search-icon {
        color: var(--rently-text-on-accent) !important;
    }

    /* The desktop search FIELD itself: give it a translucent-WHITE fill so it reads as a raised input on the
       dark bar (mirrors how the lab raises controls on its solid finish), and force its typed text + placeholder
       to white / translucent-white. The field has its OWN resting white card on hairline; on solid we override.
       (.search-open keeps its existing brighter open-state fill below — this is the resting field.)
       G5 HYBRID (user decision 2026-07-22): the field keeps the proposal's WHITE card treatment ON the
       dark solid bar — white input + white address section + the red Search button — instead of the
       old translucent-white dimming. Token-driven, so dark mode flips the field to the dark card.
       G4 (2026-07-22): the white card moved DOWN a level. The stack is now transparent (it is only the
       flex container that separates the three chips), so painting the card here would draw one sheet
       BEHIND the split elements and defeat the separation. Each chip carries its own card instead —
       which is exactly what the base rules already do, so the solid bar only needs the stack's old
       card/border explicitly cleared. */
    [data-search-nav-surface="solid"] .search-nav-appbar .search-bar-stack {
        background-color: transparent;
        border: 0;
    }

    /* ...but the OPEN state still needs a ground. When the three chips fuse, the active half is a
       raised white card and the inactive half goes transparent — on hairline/glass that transparency
       falls through to the stack's own open-state --rently-subtle-bg, but on solid the rule above has
       just cleared it, so the inactive half would show the dark accent bar straight through and the
       fused bar would look half-missing. Restore the card for the open state only (this is what the
       stack's solid card used to provide before the split moved it down to the chips).
       (0,4,0) so it beats the (0,3,0) clear above. */
    [data-search-nav-surface="solid"] .search-nav-appbar .search-bar-stack.search-open {
        background-color: var(--rently-card-bg);
    }

    /* NOTE the real DOM (QA-verified): the search <input> ITSELF carries .search-input (Radzen textbox
       — no inner input). G4: the magnifier .search-icon is no longer a direct child of
       .search-bar-stack — it now lives INSIDE .search-input-section. It is still a descendant, so the
       descendant selectors below are unaffected; only the "direct child" claim changed. */
    [data-search-nav-surface="solid"] .search-nav-appbar input.search-input,
    [data-search-nav-surface="solid"] .search-nav-appbar .search-location-input input {
        color: var(--rently-text-body) !important;
    }

    /* Counter the solid catch-all whitening for everything INSIDE the white field (longer selectors at
       equal !important): icons go accent-text (mock recipe), typography goes body ink, the divider back
       to muted body ink. Scoped so the RED .search-button (also inside the stack) keeps its white
       label/icon. */
    [data-search-nav-surface="solid"] .search-nav-appbar .search-bar-stack .search-icon,
    [data-search-nav-surface="solid"] .search-nav-appbar .location-picker-section .mud-icon-root,
    [data-search-nav-surface="solid"] .search-nav-appbar .date-picker-section .mud-icon-root {
        color: var(--section-accent-text, var(--rently-primary-dark)) !important;
    }

    [data-search-nav-surface="solid"] .search-nav-appbar .search-input-section .mud-typography,
    [data-search-nav-surface="solid"] .search-nav-appbar .location-picker-section .mud-typography,
    [data-search-nav-surface="solid"] .search-nav-appbar .date-picker-section {
        color: var(--rently-text-body) !important;
    }

    [data-search-nav-surface="solid"] .search-nav-appbar .search-bar-stack .search-divider {
        color: var(--rently-text-body) !important;   /* the base rule's 0.3 opacity keeps it muted */
    }

    /* Tablet + mobile trigger fields get the same white-card treatment so the hybrid is coherent
       across breakpoints; their labels/icons revert from the whitened catch-all to readable ink. */
    [data-search-nav-surface="solid"] .tablet-search-bar .tablet-search-field,
    [data-search-nav-surface="solid"] .mobile-search-bar .mobile-search-field {
        background-color: var(--rently-card-bg);
        border: 1px solid var(--rently-border);
    }

    [data-search-nav-surface="solid"] .tablet-search-bar .tablet-search-field .mud-icon-root,
    [data-search-nav-surface="solid"] .tablet-search-bar .tablet-search-field .search-icon,
    [data-search-nav-surface="solid"] .tablet-search-bar .tablet-search-field .tablet-search-label,
    [data-search-nav-surface="solid"] .tablet-search-bar .tablet-search-field .mud-typography,
    [data-search-nav-surface="solid"] .mobile-search-bar .mobile-search-field .mud-icon-root,
    [data-search-nav-surface="solid"] .mobile-search-bar .mobile-search-field .search-icon,
    [data-search-nav-surface="solid"] .mobile-search-bar .mobile-search-field .mobile-search-label,
    [data-search-nav-surface="solid"] .mobile-search-bar .mobile-search-field .mud-typography {
        color: var(--rently-text-body) !important;
    }

    /* Placeholder = the standard muted secondary ink on the white field (theme-aware; the dark-mode
       placeholder lift further below still applies). */
    [data-search-nav-surface="solid"] .search-nav-appbar input.search-input::placeholder,
    [data-search-nav-surface="solid"] .search-nav-appbar .search-location-input input::placeholder {
        color: var(--rently-text-secondary) !important;
    }

    /* Drawer backdrop improvements */
    .drawer-backdrop {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: rgba(0, 0, 0, 0.5);
        z-index: var(--z-drawer-backdrop);
        touch-action: none;
        -webkit-touch-callout: none;
        -webkit-user-select: none;
        -khtml-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
        opacity: 0;
        visibility: hidden;
        transition: opacity 0.3s ease, visibility 0.3s ease;
    }

    .drawer-backdrop.visible {
        opacity: 1;
        visibility: visible;
    }

    /* Fix drawer positioning */
    .mobile-nav-drawer,
    .mobile-user-drawer {
        position: fixed !important;
        z-index: var(--z-drawer) !important;
    }

    /* Fix MudDrawer overlay z-index */
    .mud-overlay-drawer {
        z-index: var(--z-drawer-backdrop) !important;
    }

    .mud-drawer-overlay {
        z-index: var(--z-drawer-backdrop) !important;
    }

    /* Closed Temporary MudDrawers are held off-screen by MudBlazor 9.4 via a physical `right: -<width>px`
       (NOT a transform) — so the two former `.mud-drawer-close-left/-right { transform: translateX(±100%) }`
       rules here were DEAD: that class is v6-era; the closed <aside> now gets `mud-drawer--closed
       mud-drawer-pos-right`, and no markup applies the old class. (Re-pointing them at the real closed class
       would have DOUBLED the offset on top of Mud's `right:-320px` and worsened overflow.) Removed — the
       off-screen drawer is instead clamped at the viewport by the `html` rule below. */

    /* Prevent horizontal scroll (WCAG 1.4.10 Reflow).
       `body { overflow-x }` CANNOT clip a `position:fixed` descendant — the right user-drawer sits off-screen at
       `right:-320px` when closed, and a fixed element's containing block is the viewport/ICB, not <body>. Only
       overflow on the ROOT element propagates to the viewport, so `html { overflow-x: clip }` is what actually
       clamps the off-screen drawer (and any stray right-edge bleed). `clip` (not `hidden`): establishes no
       scroll container, doesn't break `position:sticky`, and — paired with the default `overflow-y: visible` —
       does not coerce the Y axis to `auto`, so vertically-overflowing popovers/menus/tooltips are untouched.
       The drawer's slide-in is preserved (Mud animates `right`; the open drawer sits at `right:0`, never
       clipped). The `body` guard is kept belt-and-braces for in-flow content. */
    html {
        overflow-x: clip;
    }

    body {
        /* clip, NOT hidden (Session-5 H1, 2026-07-24): `hidden` coerces overflow-y to `auto`,
           making <body> a scroll container — and since the `html` rule above is non-visible,
           body's overflow does NOT propagate to the viewport, so body sat as a never-scrolling
           scrollport that captured every position:sticky on the platform (the same trap the
           .rz-body document-scroller contract in site.css removes, one level up). `clip` clips
           in-flow bleed identically while establishing no scroll container. */
        overflow-x: clip !important;
    }

    /* S7-06 verdict — KEEP. position:fixed on <body> takes the whole page out of flow, so frame 0 of
       every drawer open pays a full-document relayout, which is a real and measurable cost right at
       the start of the 225ms slide. It stays because it is the only technique that actually holds on
       iOS Safari: overflow:hidden on body does not stop touch scrolling there, and the page scrolls
       behind the open drawer without this. An accessibility-and-correctness win at a one-frame price.
       Reconsider only if a per-frame capture shows this relayout dominating now that the drawers are
       no longer being torn down and rebuilt on every toggle (S7-06 Phase 1a) — that remount was the
       far larger cost and was masking this one. */
    body.drawer-open {
        overflow: hidden !important;
        position: fixed !important;
        width: 100% !important;
        height: 100% !important;
        touch-action: none !important;
    }

    /* F2 (session 5): lock the DOCUMENT scroller while the category mega-menu is open. The nav
       bar is in-flow (MudAppBar Fixed="false" inside a position:static RadzenHeader) while the
       mega-popover + scrim are viewport-fixed, pinned to --rently-mainnav-height — so any page
       scroll detached them from the bar. Locking the root makes the detach structurally
       impossible. ROOT element on purpose: per the doctrine above, body's overflow does NOT
       propagate to the viewport once html is non-visible — which is also why MudOverlay's
       body-level scroll lock was silently inert here (CategoryNav now sets LockScroll="false",
       removing its stray 8px body padding too). Zero width shift: html{scrollbar-gutter:stable}
       (rently-dashboard-tokens.css) keeps the gutter reserved while overflow-y is hidden.
       Desktop-only by construction — .browse-rentables-btn only renders ≥Md; the mobile drawer
       keeps body.drawer-open above. Same :has() gate idiom as the N1 will-change release. */
    html:has(.browse-rentables-btn.popover-open) {
        overflow-y: hidden;
    }

    /* Logout form styles (S9: .logout-form itself is gone — the desktop nav form is
       .user-menu-logout since S8-06; only the mobile twin still renders this class) */
    .logout-form-mobile {
        display: inline-block;
        margin: 0;
        padding: 0;
    }

    /* Animation Classes */
    @keyframes fadeIn {
        from {
            opacity: 0;
        }

        to {
            opacity: 1;
        }
    }

    @keyframes slideIn {
        from {
            transform: translateX(-10px);
            opacity: 0;
        }

        to {
            transform: translateX(0);
            opacity: 1;
        }
    }

    @keyframes slideInRight {
        from {
            transform: translateX(10px);
            opacity: 0;
        }

        to {
            transform: translateX(0);
            opacity: 1;
        }
    }

    @keyframes slideInUp {
        from {
            transform: translateY(10px);
            opacity: 0;
        }

        to {
            transform: translateY(0);
            opacity: 1;
        }
    }

    @keyframes main-nav-pulse {
        0% {
            transform: scale(1);
        }
        50% {
            transform: scale(1.05);
        }
        100% {
            transform: scale(1);
        }
    }

    .main-nav-animate-in {
        animation: fadeIn 0.3s ease-out;
    }

    .slide-in {
        animation: slideIn 0.3s ease-out;
    }

    .slide-in-right {
        animation: slideInRight 0.3s ease-out;
    }

    .slide-in-up {
        animation: slideInUp 0.3s ease-out;
    }

    /* Staggered animations for menu items */
    .menu-item:nth-child(1) { animation-delay: 0.05s; }
    .menu-item:nth-child(2) { animation-delay: 0.10s; }
    .menu-item:nth-child(3) { animation-delay: 0.15s; }
    .menu-item:nth-child(4) { animation-delay: 0.20s; }
    .menu-item:nth-child(5) { animation-delay: 0.25s; }

    /* S7-06 — the step is 0.03s, was 0.05s. The drawer's own slide is MudBlazor's stock 225ms, and at
       0.05s the 7th row did not even begin its entrance until 0.35s — 125ms after the drawer had come
       to a complete stop. Rows were still arriving into a panel that had visibly finished moving,
       which reads as the drawer being slow rather than as a stagger. At 0.03s the last row starts at
       0.21s, so the whole cascade is under way before the slide ends and the two motions resolve
       together. The sibling .menu-item / .user-menu-item lists keep 0.05s: they are 5-item popovers
       with no 225ms envelope to fit inside. */
    .drawer-list-item:nth-child(1) { animation-delay: 0.03s; }
    .drawer-list-item:nth-child(2) { animation-delay: 0.06s; }
    .drawer-list-item:nth-child(3) { animation-delay: 0.09s; }
    .drawer-list-item:nth-child(4) { animation-delay: 0.12s; }
    .drawer-list-item:nth-child(5) { animation-delay: 0.15s; }
    .drawer-list-item:nth-child(6) { animation-delay: 0.18s; }
    .drawer-list-item:nth-child(7) { animation-delay: 0.21s; }

    .user-menu-item:nth-child(1) { animation-delay: 0.05s; }
    .user-menu-item:nth-child(2) { animation-delay: 0.10s; }
    .user-menu-item:nth-child(3) { animation-delay: 0.15s; }
    .user-menu-item:nth-child(4) { animation-delay: 0.20s; }
    .user-menu-item:nth-child(5) { animation-delay: 0.25s; }
    .user-menu-item:nth-child(6) { animation-delay: 0.30s; }

    /* Logo Styles */
    .logo-link {
        display: inline-block;
        justify-self: start;
        width: fit-content;
        line-height: 0;
        transition: transform 0.2s ease;
    }

    .logo-link:hover {
        transform: scale(1.02);
    }

    .logo-link:focus-visible {
        outline: 2px solid var(--section-accent-text, var(--rently-primary-dark));
        outline-offset: 2px;
        border-radius: var(--rently-radius-md, 8px);
    }

    .logo-loading {
        opacity: 0;
        transition: opacity 0.3s ease;
    }

    .logo-loaded {
        opacity: 1;
        animation: fadeIn 0.3s ease-out;
    }

    /* Skeleton Styles */
    .user-skeleton-container {
        display: flex;
        align-items: center;
        gap: 12px;
    }

    .notification-skeleton {
        display: flex;
        align-items: center;
        justify-content: center;
        height: 40px;
    }

    .mobile-user-card-skeleton {
        display: flex;
        align-items: center;
        gap: 4px;
        padding: 4px 8px 4px 4px;
        border-radius: 24px;
        background-color: rgba(0, 0, 0, 0.04);
    }

    /* Error States */
    .user-error-state {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 8px;
    }

    /* User Card Enhancements */
    .user-avatar {
        transition: transform 0.2s ease;
    }

    .mobile-user-avatar {
        transition: transform 0.2s ease;
    }

    .mobile-user-card:hover .mobile-user-avatar {
        transform: scale(1.05);
    }

    /* Original styles with performance improvements */
    /* Top-nav proposal G2 (2026-07-22): divider ink derives from the theme-aware body ink at 22%
       (mock's .tnx-nav__divider recipe) instead of the fixed #ccc, so it holds in dark too. */
    /* G4 (2026-07-22): now a real 1px x 20px rule (the mock's .tnx-nav__divider) instead of a typed
       "|" glyph, whose weight/height drifted with the font. It keeps driving itself from `color` via
       background: currentColor SPECIFICALLY so the existing ink overrides below — the solid-bar
       white-flip and the [data-theme=dark] border-strong lift — keep working untouched. */
    .nav-divider {
        display: inline-block;
        flex-shrink: 0;
        width: 1px;
        height: 20px;
        margin-inline: 6px;
        background: currentColor;
        color: color-mix(in srgb, var(--rently-text-body) 22%, transparent);
        user-select: none;
    }

    /* Desktop Styles */
    .main-nav-container {
        width: var(--rently-layout-max-width, 1440px);
        margin-left: auto;
        margin-right: auto;
        /* N2 (2026-07-24): three-zone grid — logo | centered actions | user cluster. The 1fr sides
           keep the Browse / Post A Rentable / Need help? cluster truly centered in the bar, while
           still yielding room when a side zone's content needs it (an fr column never shrinks below
           its content, so tight widths degrade to near-center instead of overlapping). */
        display: grid;
        grid-template-columns: 1fr auto 1fr;
        align-items: center;
    }

    .nav-center-cluster {
        min-width: 0;
    }

    .nav-right-cluster {
        display: flex;
        align-items: center;
        justify-content: flex-end;
        min-width: 0;
    }

    /* Help Link — top-nav proposal G2 (2026-07-22): neutral body ink (was inline #555), accent-text on
       hover; theme-aware token needs no dark lift. !important beats MudLink's .mud-*-text role class. */
    .help-link {
        color: var(--rently-text-body) !important;
        transition: all 0.2s ease;
    }

    .help-link:hover {
        transform: translateY(-1px);
        color: var(--section-accent-text, var(--rently-primary-dark)) !important;
    }

    /* User Menu Enhancements */
    .user-menu {
        transition: all 0.3s ease;
    }

    .user-menu-popover {
        animation: slideInUp 0.2s ease-out;
    }

    /* User Menu Container for custom popover */
    .user-menu-container {
        position: relative;
        display: inline-block;
    }

    /* User Menu Dropdown Content — G4: onto the shared popover recipe. The 4px radius was the odd one
       out (the brand radius is 8px and every other nav surface uses it), and it was the only one of the
       four nav popovers with no edge at all, relying purely on MudPaper Elevation="4". */
    .user-menu-dropdown-content {
        min-width: 220px;
        padding: var(--rently-popover-pad) 0;
        border-radius: var(--rently-popover-radius);
        border: 1px solid var(--rently-border);
        box-shadow: var(--rently-popover-shadow) !important;   /* beats .mud-elevation-4 */
        overflow: hidden;   /* clips the first/last .menu-item hover against the new radius */
    }

    /* Item hover — one wash shared by the account menu and the search-result rows below. */
    .user-menu-dropdown-content .menu-item:hover {
        background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 8%, transparent);
    }

    /* S8-06 §3a / S11-01 — Logout relocated INTO this popover (bottom, after the role-gated links).
       These rules live here rather than in a .razor.css because MudPopover portals its content out to
       the provider island, where scoped CSS never matches.

       S11-01: the markup dropped .mud-nav-link for the house .rently-btn--destructive-outline recipe,
       so this block stops chasing .menu-item's silhouette and finishes the button instead. The
       reference implementation is .mobile-logout-submit-btn further down this file (1424-1462) — the
       mobile drawer has had exactly this button for a long time; the desktop popover is catching up.
       Two deliberate changes from the S8-06 version:
         - border-radius:0 is DELETED. That square edge was the whole menu-row look; it existed to sit
           flush against the popover's clipped corners, and a bordered button inside a padded popover
           has no edge to sit flush against.
         - the colour is now restated HERE. .rently-btn--destructive-outline paints its ink at (0,1,0)
           with no !important, which cannot beat .logout-button's (0,1,0)!important resting neutral at
           ~918 — the button would have carried a red BORDER around grey TEXT. This rule is (0,2,0)
           with !important, which does beat it.

       SPECIFICITY IS LOAD-BEARING throughout this block. .logout-button ~918 is (0,1,0)!important and
       its hover pair ~933 is (0,3,0)!important. Everything below is written to clear those and nothing
       more; do not "simplify" a selector here without re-deriving both. */
    /* The horizontal gutter the OUTLINED button needs. .user-menu-dropdown-content is
       `padding: var(--rently-popover-pad) 0` — vertical only, which is correct for .menu-item rows
       whose hover wash is meant to run full-bleed to the popover edge. It was also the right partner
       for logout's old `border-radius: 0` menu-row silhouette. S11-01 replaced that with a bordered
       button, and a full-bleed bordered button lays its 1px outline directly on the popover's own 1px
       border with zero gap — plus `overflow: hidden` clips its corners against the popover radius.
       The gutter belongs here rather than on the container, so the menu rows above keep their bleed. */
    .user-menu-logout {
        display: block;
        width: 100%;
        margin: 0;
        padding: 0 var(--rently-popover-pad, 8px);
    }

    /* (0,2,0)!important — beats the (0,1,0)!important resting ink at ~918 and the (0,1,0) geometry
       group at ~1509 (which still supplies the 44px target and the 8px radius; leave it alone). */
    .user-menu-logout .logout-button {
        width: 100%;
        justify-content: center;
        padding: 0 16px;
        color: var(--rently-critical-text-strong, #b91c1c) !important;
        border: 1px solid var(--rently-critical-text-strong, #b91c1c);
    }

    /* (0,4,0) — beats the (0,3,0)!important hover pair at ~933 for the two properties that rule does
       NOT mark important (its background-color and, implicitly, the border). The INK it sets there is
       already --rently-critical-text-strong, i.e. the same value this block rests at, so there is
       nothing left for the hover to change about the text and no !important needed here.
       The wash mixes from --rently-btn-destructive: a background tint carries no text-contrast duty, so
       it can stay the brand fill red while the ink stays the AA-safe -strong token. */
    .user-menu-logout .logout-button:hover:not(:disabled),
    .user-menu-logout .logout-button:focus-visible:not(:disabled) {
        background-color: color-mix(in srgb, var(--rently-btn-destructive, #c7351f) 8%, transparent);
        border-color: var(--rently-critical-text-strong, #b91c1c);
    }

    /* Disabled mutes the EDGE only. The shared .logout-button:disabled already drops opacity to 0.6,
       which carries the ink; muting the ink again here would double-fade it into the popover. */
    .user-menu-logout .logout-button:disabled {
        border-color: var(--rently-border, #e5e7eb);
    }

    /* Focus ring drawn INSIDE the box. The house .rently-btn:focus-visible offsets its outline +2px to
       expose the page frost behind the button, which is right on a padded page and wrong here: this
       button is full-width inside .user-menu-dropdown-content, which carries overflow:hidden and zero
       horizontal padding, so an outward ring would be sliced off at both edges — a required focus
       indicator that is only partly visible still fails SC 2.4.7. (0,3,0) beats the (0,2,0) house rule;
       only the offset changes, so the ring keeps the house colour and width. */
    .user-menu-logout .logout-button:focus-visible {
        outline-offset: -2px;
    }

    /* The in-flight spinner is a MudProgressCircular with Color="Color.Inherit", which resolves to
       currentColor — restate it so the ring is the button's red and not the palette's teal. */
    .user-menu-logout .logout-button .mud-progress-circular {
        color: currentColor;
    }

    /* Navigation shortcut icon wrapper - absolutely positioned over dropdown arrow */
    .user-menu-nav-shortcut-wrapper {
        position: absolute;
        right: 2px;
        top: 50%;
        transform: translateY(-50%);
        z-index: 10;
    }

    /* Navigation shortcut icon styles for user menu */
    .user-menu-nav-shortcut {
        min-width: 24px !important;
        width: 24px !important;
        height: 24px !important;
        padding: 2px !important;
        color: white !important;
        background-color: var(--rently-secondary) !important;
        border-radius: 50% !important;
        animation: fadeInScale 0.2s ease-out;
    }

    .user-menu-nav-shortcut:hover {
        transform: scale(1.1) !important;
        background-color: #d63520 !important; /* C4: converge to the secondary-red ramp (no exact token yet) */
    }

    .user-menu-nav-shortcut:focus-visible {
        outline: 2px solid white;
        outline-offset: 2px;
    }

    @keyframes fadeInScale {
        from {
            opacity: 0;
            transform: scale(0.8);
        }
        to {
            opacity: 1;
            transform: scale(1);
        }
    }

    /* Dropdown arrow icon - nudged right to align with nav shortcut position */
    .dropdown-arrow-icon {
        margin-left: 10px;
        margin-right: -4px;
    }

    /* User Card Classes — top-nav proposal G4 (2026-07-22): the mock's cluster is BARE at rest
       (.tnx-nav__user has padding + radius but NO fill, border or shadow), and the accent wash becomes
       a hover/open affordance instead of a permanent tile. The Pt3.C-ii 30% accent border stays retired.
       The dropshadow that prompted this was MudPaper's default Elevation=1 — fixed at the call site
       (MainNav.razor) with Elevation="0"; nothing here ever declared a shadow. */
    .user-card {
        cursor: pointer;
        position: relative; /* For absolute positioning of nav shortcut */
        background: transparent;
        border-radius: var(--rently-radius-md, 8px);
        transition: background-color var(--rently-transition-fast, 0.15s ease);
    }

    /* The chip. Mixes into TRANSPARENT (not --rently-card-bg): the card now sits directly on the nav
       surface, which differs per finish (white hairline / frosted glass / dark solid), so a wash that
       carried its own opaque ground would punch a light tile through the glass and solid bars. */
    .user-menu-container:hover .user-card,
    .user-card[aria-expanded="true"] {
        background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 12%, transparent);
    }

    @media (prefers-reduced-motion: reduce) {
        .user-card {
            transition: none;
        }
    }

    /* Mock cluster pieces: a shared circular accent-wash ground behind the photo / Gravatar glyph,
       the .82rem/700 greeting, and the .68rem muted role sublabel (replaces the static "My Account"
       second line — and the retired role-colour slice as the role indicator). */
    .user-avatar-ring {
        width: 40px;
        height: 40px;
        border-radius: 50%;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        overflow: hidden;
        flex-shrink: 0;
        background: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 22%, var(--rently-card-bg));
    }

    .user-avatar-ring img {
        border-radius: 50%;
    }

    .user-card-text {
        padding-inline: 8px 2px;
    }

    /* Body/secondary ink (the mock's --tnx-on / --tnx-muted), NOT the section accent: the card's fill
       is a light accent wash, on which the accent ink measured only 3.97:1 in dark (SC 1.4.3 FAIL at
       this size). Both tokens are theme-aware, so they stay AA on the wash in either mode. */
    .user-card-hi {
        font-size: 0.82rem !important;
        font-weight: 700 !important;
        line-height: 1.15 !important;
        color: var(--rently-text-body) !important;
    }

    .user-card-role {
        font-size: 0.68rem !important;
        line-height: 1.15 !important;
        color: var(--rently-text-secondary) !important;
    }

    .user-card .dropdown-arrow-icon {
        color: var(--rently-text-body);
    }

    .user-card.loading {
        pointer-events: none;
        opacity: 0.7;
    }

    /* Button States */
    .login-button {
        transition: all 0.2s ease;
    }

    .login-button:hover {
        transform: translateY(-1px);
    }

    /* Top-nav proposal G4 (2026-07-22): Logout is the LAST red item in the bar (G2 flipped
       Post-A-Rentable to neutral), which is why it read as detached rather than paired with the
       account card. It now rests in neutral body ink on the shared nav-link silhouette and reveals
       the brand red only on hover/focus — affordance preserved, shout removed.
       No translateY here: no other item in the bar lifts, and the lift is what made it read as a
       separate control floating beside the card. */
    .logout-button {
        color: var(--rently-text-secondary) !important;
        background-color: transparent;
        gap: 6px;
        transition: color var(--rently-transition-fast, 0.15s ease),
                    background-color var(--rently-transition-fast, 0.15s ease);
    }

    /* The hover ink is --rently-critical-text-strong, NOT the raw brand --rently-secondary. Measured on
       the live hovered nav bar: #EF412C is 3.14:1 (SC 1.4.3 FAIL at 13.12px/600) while #b91c1c is
       5.28:1. --rently-secondary stays the brand's FILL red (the Search button, CTAs); this token is
       the house red for TEXT that has to clear AA, and it is theme-aware so dark lifts on its own.
       The wash still mixes from --rently-secondary — a background tint carries no text-contrast duty,
       so the hover still reads as brand red. Before this pass Logout was raw brand red in EVERY state,
       i.e. 3.14:1 at rest too; the neutral resting ink now measures 6.84:1. */
    .logout-button:hover:not(:disabled),
    .logout-button:focus-visible:not(:disabled) {
        color: var(--rently-critical-text-strong, #b91c1c) !important;
        background-color: color-mix(in srgb, var(--rently-secondary) 8%, transparent);
    }

    .logout-button:disabled {
        opacity: 0.6;
        cursor: not-allowed;
    }

    @media (prefers-reduced-motion: reduce) {
        .logout-button {
            transition: none;
        }
    }

    /* Mobile Styles */
    .mobile-logo {
        display: flex;
        align-items: center;
        justify-content: center;
        transition: transform 0.2s ease;
    }

    .mobile-logo:active {
        transform: scale(0.95);
    }

    .mobile-logout-btn {
        background: none;
        border: none;
        color: inherit;
        font: inherit;
        cursor: pointer;
        padding: 0;
        width: 100%;
        text-align: left;
    }

    /* Mobile User Card */
    .mobile-user-card {
        /* Mobile nav toggles a11y — now a native <button>: neutralise UA button chrome so it stays visually
           identical to the former MudPaper (background is set inline by GetMobileUserCardStyle(); replicate
           MudPaper's default Elevation=1 resting shadow). */
        appearance: none;
        -webkit-appearance: none;
        font: inherit;
        color: inherit;
        text-align: inherit;
        margin: 0;
        box-sizing: border-box;
        box-shadow: var(--mud-elevation-1);
        cursor: pointer;
        border-radius: 24px;
        /* Pt3.C-ii — section-accent edge so the tiny light-wash card reads on the white Hairline bar. */
        border: 1px solid color-mix(in srgb, var(--section-accent, var(--rently-primary)) 30%, transparent);
        padding: 4px 8px 4px 4px;
        display: flex;
        align-items: center;
        transition: all 0.2s ease;
        /* S7-06: will-change:transform removed — nothing here animates transform, so it only forced a
           standing compositor layer on a card that is present on every mobile page load. */
    }

    /* a11y: visible keyboard focus ring (WCAG 2.4.7 + 1.4.11 ≥3:1) — section-accent-text reads on the light wash. */
    .mobile-user-card:focus-visible {
        outline: 2px solid var(--section-accent-text, var(--rently-primary-dark));
        outline-offset: 2px;
    }

    /* Lose-nothing: the former MudPaper <div> had no disabled state — keep the native button visually unchanged
       during the sub-second drawer transition (no UA greyance, no hand-cursor on a momentarily-disabled control). */
    .mobile-user-card:disabled {
        opacity: 1;
        cursor: default;
    }

        .mobile-user-card:hover {
            transform: translateY(-1px);
            box-shadow: 0 2px 8px rgba(0,0,0,0.15);
        }

        .mobile-user-card:active {
            transform: scale(0.98);
        }

    .mobile-user-content {
        display: flex;
        align-items: center;
    }

    /* ══ S12-05b — THE nav count badge, one recipe for both icons ═══════════════════════════════════
       "The Cart icon in the Nav has a completely different looking number indicator to our
       Notification icon."

       It did, and the cause was ownership rather than taste. The bell carried a bespoke slim pill in
       NotificationMenu.razor's own inline style block; the cart had exactly ONE declaration in this
       file (`vertical-align: middle`, below) and therefore rendered MudBlazor's stock badge — 20px
       tall, 10px radius, 12px type, Color.Error red. Two adjacent icons in the same nav cluster, drawn
       to two different recipes, with nothing structural stopping them drifting further apart.

       This class now owns the pill for BOTH. The bespoke block was DELETED from NotificationMenu
       rather than left alongside it: that sheet is an in-body inline <style>, which is later in
       source order than this head-linked file and so wins every equal-specificity tie. Leaving both
       would mean the shared class quietly losing on the bell and winning on the cart — the same
       divergence in a new costume, and harder to spot the second time.

       :not(.mud-badge-dot) is a deliberate guard, not decoration. NotificationMenu ASKS MudBlazor for
       the dot variant when the unread count is zero. That request is unreachable as things stand,
       because Visible is bound to the same condition inverted — the badge is hidden in exactly the
       state that would draw a dot — but flip either binding and the dot is live tomorrow. MudBlazor's
       own dot geometry (9px square, 50% radius, no padding) is right for it; this pill must not reach
       it, and a guard costs nothing today.

       The MudBadge Color parameters are deliberately LEFT ALONE (Color.Error on the cart,
       GetBadgeColor() on the bell) even though the !important background makes them cosmetically
       inert for the count pill: they still drive the dot variant and Mud's own theme classes, so
       stripping them would be a behaviour change dressed as a cleanup.

       Selector shape is the recipe QA verified against the live MudBlazor 9.7 DOM: the badge element
       is `.mud-badge`. The v6-era `.mud-badge-wrapper .mud-badge-badge` has never matched since the
       v9 upgrade (see the note further down where the dead pulse rule used to live). At (0,3,0) this
       also clears MudBlazor's own single-class `.mud-badge` base rule without depending on which of
       the two sheets the browser loaded last. */
    .rently-nav-count .mud-badge:not(.mud-badge-dot) {
        min-width: 18px;
        height: 18px;
        padding: 0 4px;
        font-weight: 700;
        font-size: 0.66rem;
        line-height: 1;
        color: #ffffff !important;
        background: var(--rently-critical, #dc2626) !important;
        border-radius: var(--rently-radius-full, 999px);
    }

    .notification-badge {
        width: 100%;
    }

    .notification-chip {
        animation: main-nav-pulse 2s infinite;
    }

    /* ===================== Cart nav button (S7-07) =====================
       Same chrome recipe as .notification-icon-button (transition + 1.05 hover scale +
       a faint neutral wash) so the two right-cluster icons read as one pair. These rules
       live here rather than in a companion .razor.css because the component's root is a
       MudBadge/MudIconButton — Mud component roots never carry the scoped [b-xxx] attribute.

       S12-05b: the COUNT PILL is no longer this class's business — CartNavButton's BadgeClass now
       also emits .rently-nav-count (above), which is the single shared recipe. This rule keeps only
       what is genuinely cart-local. */
    .nav-cart-badge {
        vertical-align: middle;
    }

    .nav-cart-btn {
        transition: all 0.2s ease;
    }

    .nav-cart-btn:hover {
        transform: scale(1.05);
        background-color: rgba(0, 0, 0, 0.04);
    }

    /* a11y: the icon button's own focus ring is a low-contrast Mud ripple; give it the same
       accent outline the mobile user card uses (WCAG 2.4.7 + 1.4.11). */
    .nav-cart-btn:focus-visible {
        outline: 2px solid var(--section-accent-text, var(--rently-primary-dark));
        outline-offset: 2px;
    }

    /* Mobile top bar: 36px to match the user-card avatar beside it (desktop stays Mud's 40px). */
    .nav-cart-btn--compact {
        width: 36px;
        height: 36px;
        padding: 6px;
    }

    /* Dark: the light wash is invisible on the dark bar — lift it, exactly as the
       notification icon does. */
    [data-theme="dark"] .nav-cart-btn:hover {
        background-color: rgba(255, 255, 255, 0.08);
    }

    /* Reduced motion — LAST in this block so it can suppress the rules above it. Assert
       transition-property:none in QA, not a 0s duration. */
    @media (prefers-reduced-motion: reduce) {
        .nav-cart-btn {
            transition: none;
        }

        .nav-cart-btn:hover {
            transform: none;
        }
    }

    /* Mobile Login Button */
    .mobile-login-button {
        transition: all 0.2s ease;
    }

    .mobile-login-button:active {
        transform: scale(0.95);
    }

    /* User Drawer Styles */
    .mobile-user-drawer {
        background-color: var(--rently-card-bg); /* C5 Pt3c.C: token-swap (light #fff, flips slate on dark) */
    }

    .user-drawer-wrapper {
        display: flex;
        flex-direction: column;
        height: 100%;
    }

    .user-drawer-header {
        padding: 20px;
        color: white;
        position: relative;
        flex-shrink: 0;
        transition: background-color 0.3s ease;
    }

    /* (C2 Pt3.B) Removed 3 inert ::deep rules — ::deep compiles only in scoped *.razor.css; in this global sheet they styled nothing. */

    /* User Drawer Content */
    .user-drawer-content {
        flex: 1;
        overflow-y: auto;
        padding-bottom: 20px;
        -webkit-overflow-scrolling: touch;
    }

    /* User Drawer Navigation */
    .user-drawer-nav {
        padding-top: 8px;
    }

    /* User Drawer Footer */
    .user-drawer-footer {
        padding: 16px;
        border-top: 1px solid #e0e0e0;
        background-color: #fafafa;
        flex-shrink: 0;
    }

    /* (The former second .logout-button block — font-weight 500 / text-transform none /
       padding 10px 16px — is removed: it is superseded by the shared nav-link silhouette near the end
       of the MainNav section, which gives Logout the same 44px box, 8px radius and 0.82rem/600 display
       type as Browse, Post-A-Rentable, Need-help and Login. Left in place it would not have changed the
       result — the silhouette is later in source order and wins the tie — but it would have been a
       second, contradictory owner of the same three properties.) */

    /* Responsive adjustments */
    @media (max-width: 1479px) {
        .main-nav-container {
            width: 100%;
            padding: 0 24px;
        }
    }

    @media (max-width: 959px) {
        .nav-divider {
            display: none;
        }
    }

    /* Enhanced Drawer styles */
    .mobile-nav-drawer {
        background-color: var(--rently-card-bg); /* C5 Pt3c.C: token-swap (light #fff, flips slate on dark) */
        transition: transform 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
    }

    .drawer-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 16px 20px;
        background-color: #fafafa;
        border-bottom: 1px solid #e0e0e0;
    }

    .drawer-nav-list {
        padding: 8px 0;
    }

    .drawer-list-item {
        padding: 0 !important;
        margin: 0 !important;
        animation-fill-mode: forwards;
    }

    .list-item-content {
        display: flex;
        align-items: center;
        padding: 14px 20px;
        cursor: pointer;
        /* S7-06: was `all`. Only background-color (:hover, :active) and transform (:active scale)
           ever change, and `all` additionally animated every inherited/unrelated property on any
           repaint — including the section-accent colour swaps. There are up to 14 of these rows in
           an open drawer, so the difference is per-row, per-frame. */
        transition: background-color 0.2s ease, transform 0.2s ease;
        width: 100%;
        /* S7-06: will-change:background-color removed — background-color is not a compositable
           property, so the hint bought no compositor fast path and only forced a layer per row. */
        position: relative;
        overflow: hidden;
    }

    /* S7-06: the sweep animates TRANSFORM, not `left`. Animating `left` on an absolutely-positioned
       ::before relayouts the row on every frame of a 0.5s hover sweep, x14 rows; translateX runs on
       the compositor. Geometry is identical: left:0 + translateX(-100%) starts exactly where
       left:-100% did, and the parent's overflow:hidden still clips it. */
    .list-item-content::before {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--section-accent, var(--rently-primary)) 5%, transparent), transparent);
        transform: translateX(-100%);
        transition: transform 0.5s ease;
    }

    .list-item-content:hover::before {
        transform: translateX(100%);
    }

    .list-item-content:hover {
        background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 8%, transparent);
    }

    .list-item-content:active {
        background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 12%, transparent);
        transform: scale(0.98);
    }

    .list-item-icon {
        margin-right: 16px;
        transition: transform 0.2s ease;
    }

    .list-item-content:hover .list-item-icon {
        transform: scale(1.1);
    }

    .drawer-subheader {
        font-weight: 600;
        color: var(--section-accent-text, var(--rently-primary-dark));
        padding: 8px 20px;
        font-size: 0.875rem;
        text-transform: none;
        letter-spacing: 0.5px;
        opacity: 0;
        animation: fadeIn 0.3s ease-out 0.3s forwards;
    }

    /* Fix MudList default styles */
    .drawer-nav-list .mud-list-item {
        padding: 0 !important;
        margin: 0 !important;
    }

    .drawer-nav-list .mud-list-item-text {
        padding: 0 !important;
        margin: 0 !important;
    }

    .drawer-nav-list .mud-list-item .mud-list-item-icon {
        min-width: unset !important;
        margin: 0 !important;
    }

    /* Touch-friendly adjustments */
    @media (hover: none) and (pointer: coarse) {
        .list-item-content {
            min-height: 48px;
        }

        .mobile-user-card:active {
            transform: scale(0.95);
        }

        .user-menu-item {
            min-height: 44px;
        }
    }

    /* scrollbars: universal kit (rently-dashboard-tokens.css N3) */

    /* Safe area support */
    @supports (padding: max(0px)) {
        .user-drawer-footer {
            padding-bottom: max(16px, env(safe-area-inset-bottom));
        }

        .drawer-nav-list {
            padding-bottom: max(8px, env(safe-area-inset-bottom));
        }

        .mobile-nav-appbar {
            padding-top: max(8px, env(safe-area-inset-top));
        }
    }

    /* Prevent text selection during swipe */
    .mobile-nav-drawer,
    .mobile-user-drawer {
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
    }

    /* Drawer shadow enhancements */
    .mobile-nav-drawer.mud-drawer-open,
    .mobile-user-drawer.mud-drawer-open {
        box-shadow: 0 8px 10px -5px rgba(0, 0, 0, 0.2), 
                    0 16px 24px 2px rgba(0, 0, 0, 0.14), 
                    0 6px 30px 5px rgba(0, 0, 0, 0.12);
    }

    /* Performance optimizations */
    * {
        -webkit-tap-highlight-color: transparent;
    }

    /* S7-06 — the unscoped reduced-motion block that stood here is GONE. It read:
           @media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important;
             animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } }
       Three problems, and they compounded:
         · `*` with !important reached every element on the page, so THREE other stylesheets
           (catalogue-map, reconnect-modal, notification-templates) were silently relying on a rule
           declared in the nav sheet. They now carry their own end-of-file guards.
         · it set a 0.01ms DURATION, not `none`. transition-property stays live, transitionend still
           fires, and the house QA probe — which asserts transition-property: none per element — could
           never verify it. Chrome also emulates 0.01ms as 1e-05s, so even a duration probe is unsafe.
         · it sat mid-file, above most of the rules it was meant to suppress, which is the arrangement
           the G6 note at the end of this file exists to forbid.
       Its coverage now lives in THE consolidated block at the end of this file. Do not reintroduce a
       reduced-motion rule here — add selectors there. */

    /* ════════════════════════════════════════════════════════════════════════════════════════════════
       Initiative C · C5 Pt3c.C — DARK chrome (MainNav). The hairline-default appbar already auto-darkens
       (its surface/border use var(--rently-card-bg)/--rently-border), and the user/nav DRAWERS flip via the
       var(--rently-card-bg) token-swap above. These DARK-ONLY rules re-colour the remaining off-palette grays
       (no token equal) so the LIGHT literals stay byte-identical. Driven by data-theme="dark" on <html>
       (App.razor boot script) — attribute-based, so it tracks the per-user Light/Dark/System toggle (C5 Pt3b),
       NOT just the OS; that is why this replaces the old prefers-color-scheme stub. */
    [data-theme="dark"] .nav-divider {
        color: var(--rently-border-strong);
    }

    /* a11y (C5 Pt3c.C): the mobile-drawer "Need help?" item (MainNav.razor:497) is a MudText with inline
       color:#555 and NO .mud-primary-text, so #555 actually applies → ~2.0:1 on the dark drawer (#1e293b),
       failing SC 1.4.3. Lift it to text-tertiary #94a3b8 = 5.7:1 (AA, browser-measured) in dark, keeping its
       muted-helper intent; the author !important beats the inline non-important style and light keeps #555.
       NOTE: the DESKTOP .help-link (MainNav.razor:82) is a MudLink carrying .mud-primary-text, whose teal
       !important already overrides its inline #555 in BOTH modes — it renders brand teal (~5.2:1 on the dark
       bar, AA), so it is deliberately NOT touched here (graying it would lose the on-brand teal for no a11y gain). */
    [data-theme="dark"] a[href*="help.rently"] .mud-typography {
        color: var(--rently-text-tertiary) !important;
    }

    /* Tinted-Glass TOP nav bar on dark (data-nav-surface is "tintedglass" here, not hairline/solid).
       The light base mixes the accent into an 80%-alpha WHITE scrim → a light frosted bar that stays light on
       the dark page (light nav text becomes unreadable). Swap the scrim to dark slate (#0f172a) so the frosted
       bar goes dark while keeping the same 10% accent tint + blur. Positively keyed to the "tintedglass" value
       so it ONLY targets that surface — the hairline variant already darkens via var(--rently-card-bg), and the
       solid variant brings its own dark accent fill (below); equal-base specificity would otherwise let this win
       over them by source order. (Top nav stays on data-nav-surface; the search bar split to its own attribute.) */
    html[data-theme="dark"][data-nav-surface="tintedglass"] .main-nav-appbar,
    html[data-theme="dark"][data-nav-surface="tintedglass"] .mobile-nav-appbar {
        background: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 10%, rgba(15, 23, 42, 0.80));
    }

    [data-theme="dark"] .mobile-user-card-skeleton {
        background-color: rgba(255, 255, 255, 0.06);
    }

    [data-theme="dark"] .drawer-header {
        background-color: var(--rently-subtle-bg);
        border-bottom-color: var(--rently-border);
    }

    [data-theme="dark"] .user-drawer-footer {
        background-color: var(--rently-subtle-bg);
        border-top-color: var(--rently-border);
    }

    [data-theme="dark"] .loading-shimmer {
        background: linear-gradient(90deg, var(--rently-muted-bg) 25%, var(--rently-subtle-bg) 50%, var(--rently-muted-bg) 75%);
        background-size: 200% 100%;
    }

    /* Loading states */
    .loading-shimmer {
        background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
        background-size: 200% 100%;
        animation: shimmer 1.2s ease-in-out infinite;
    }

    @keyframes shimmer {
        0% {
            background-position: 200% 0;
        }
        100% {
            background-position: -200% 0;
        }
    }

    /* (Removed G4 2026-07-22: a "notification badge pulse" rule targeting .notification-badge
       .mud-badge-badge. That is the MudBlazor v6 badge DOM; 9.7 renders .mud-badge, so the rule has
       never matched since the v9 upgrade. The live badge is a faithful port of the mock's
       .tnx-nav__badge and deliberately does NOT pulse.
       S12-05b: that badge recipe moved OUT of NotificationMenu.razor's inline style block and into
       .rently-nav-count near the top of this file, where the cart badge shares it.) */

    /* Focus styles for accessibility */
    .mud-button:focus-visible,
    .mud-icon-button:focus-visible,
    .list-item-content:focus-visible {
        outline: 2px solid var(--section-accent-text, var(--rently-primary-dark));
        outline-offset: 2px;
    }

    /* Optimized transitions */
    .user-card,
    .mobile-user-card,
    .list-item-content,
    .login-button,
    .logout-button {
        transform: translateZ(0); /* Enable hardware acceleration */
        backface-visibility: hidden; /* Prevent flickering */
    }

    .mobile-logout-submit-btn {
    width: 100%;
    padding: 10px 16px;
    border: 1px solid var(--rently-secondary);
    background-color: transparent;
    color: var(--rently-secondary);
    font-family: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", sans-serif;
    font-size: 0.875rem;
    font-weight: 500;
    line-height: 1.75;
    letter-spacing: 0.02857em;
    text-transform: none;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.2s ease;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

.mobile-logout-submit-btn:hover:not(:disabled) {
    background-color: rgba(var(--rently-secondary-rgb), 0.08);
    transform: translateY(-1px);
}

.mobile-logout-submit-btn:active:not(:disabled) {
    transform: scale(0.98);
}

.mobile-logout-submit-btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.mobile-logout-submit-btn .mud-icon-root {
    display: inline-flex;
    vertical-align: middle;
}

/* Top-nav proposal G2 (2026-07-22): Post-A-Rentable / Create-Store adopt the mock's NEUTRAL primary-link
   treatment — body ink at rest, accent-text + the soft section pill on hover (the .login-nav-btn /
   .browse-rentables-btn idiom). The former red CTA treatment (C4 literals + the D31 dark-only red ramp)
   is retired with it; --rently-text-body is theme-aware, so no dark lift is needed. The solid bar still
   forces the label white (rules above) -> unaffected. */
.post-rentable-btn {
    color: var(--rently-text-body) !important;
    font-size: 0.82rem !important;
    font-weight: 600 !important;
}

.post-rentable-btn:hover {
    color: var(--section-accent-text, var(--rently-primary-dark)) !important;
    background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 8%, transparent) !important;
}

.login-nav-btn {
    min-height: 44px !important;
}

/* Initiative C · C2 Pt3.C-ii — primary-link pill. The Login link adopts the section accent-text + a soft pill
   on hover, matching .browse-rentables-btn. The RED (--rently-secondary) CTAs — Post-A-Rentable, Create-Store,
   logout — are deliberately EXCLUDED; they stay brand-red. Storefront (no --section-accent) falls back to the
   teal --rently-primary-dark, so the signed-out look is unchanged. */
.login-nav-btn {
    color: var(--section-accent-text, var(--rently-primary-dark)) !important;
}

.login-nav-btn:hover {
    color: var(--section-accent-text, var(--rently-primary-dark)) !important;
    background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 8%, transparent) !important;
}

/* ── Shared primary-link silhouette — top-nav proposal G4 (2026-07-22) ────────────────────────────
   The lab mock gave EVERY primary link one geometry (.tnx-nav__link): 44px box, 12px inline padding,
   --rently-radius-md, the display font at 0.82rem/600. Only .login-nav-btn ever got the 44px, so the
   bar's five interactive items sat on four different silhouettes and the accent pill (Browse's
   .popover-open / .browse-current state, and every :hover wash above) landed on mismatched shapes.

   This block owns GEOMETRY ONLY. Every colour above stays exactly where it is — the per-item rules
   are !important and win regardless of source order, so this cannot disturb the G2 neutral-ink port,
   the Browse pill states, or the solid-surface white-flip catch-alls.

   .logout-button is included: it is a bare <button> carrying MudBlazor's .mud-nav-link, which brings
   its own padding/height — the reason Logout never matched the links beside it. */
.browse-rentables-btn,
.post-rentable-btn,
.help-link,
.login-nav-btn,
.logout-button {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 12px;
    border-radius: var(--rently-radius-md, 8px);
    font-family: var(--rently-font-display, inherit);
    font-size: 0.82rem;
    font-weight: 600;
    line-height: 1.15;
    text-transform: none;
    white-space: nowrap;
}

/* ===================== SearchNav (was SearchNav.razor inline style, lines 704-1542) ===================== */
    /* Z-index Architecture — the --z-nav-normal / --z-drawer-backdrop / --z-drawer vars SearchNav
       relies on are defined once in the MainNav :root block above (identical values). The duplicate
       SearchNav :root declaration was removed during extraction to keep a single source of truth. */

    /* Fix drawer positioning */
    .mobile-search-drawer {
        position: fixed !important;
        z-index: var(--z-drawer) !important;
    }

        /* Fix MudDrawer overlay z-index */
        .mobile-search-drawer + .mud-overlay-drawer {
            z-index: var(--z-drawer-backdrop) !important;
        }

    /* Prevent body scroll when drawer is open */
    body.search-drawer-open {
        overflow: hidden !important;
        position: fixed !important;
        width: 100% !important;
        height: 100% !important;
        touch-action: none !important;
    }

    /* CSS Variables */
    :root {
        /* ══ G5 (2026-07-22) — DIRECTION-AWARE morph timing ══════════════════════════════════════════
           The split↔fuse morph used one 0.3s curve for both directions. A transition reads its timing
           from the DESTINATION state's computed style, so declaring the duration/easing as inherited
           custom properties on .search-bar-stack (base = closed = the exit timing; .search-open = the
           enter timing) gives us Material's exit-faster-than-enter asymmetry for free — every
           transition shorthand below just reads var(--search-dur) var(--search-ease) and inherits the
           right pair automatically. No JS, no duplicated shorthands. */
        /* ENTER easing is a SLOW-START curve (easeInOutCubic), and that is a measured choice, not a
           taste one. Opening the search is not a pure CSS event: the same Blazor render batch that
           adds .search-open also mounts the entire dropdown panel (results, chips, history) and the
           overlay, so the browser stalls ~40ms on style+layout before it paints again. The CSS
           transition clock runs during that stall. A front-loaded curve (the first attempt here was
           cubic-bezier(0.32,0.72,0,1)) is ~30% done by then, so the first frame the user actually
           SEES is already a third of the way through — measured as a 348px jump on a 545px morph.
           easeInOutCubic is only ~4% done at 40ms, which drops that to ~22px. Slow-start easing is
           what makes a transition robust against a framework's render-batch stall. */
        /* ══ S7-06 (2026-07-25) — the morph is now a TWO-PHASE contract ══════════════════════════════
           The paragraph above describes mitigating the render-batch stall with easing. S7-06 removes
           most of the stall instead, so read the two together:
             phase 1  0-260ms   the bar fuses against a DOM that is deliberately left alone. The
                                skeleton still mounts immediately (it is the loading affordance), but
                                nothing heavier does.
             phase 2  >=280ms   SearchNav.razor.cs AwaitMorphQuietWindowAsync releases the async
                                results assignment — up to 5 rows with images. It lands inside the
                                panel's own 220-420ms fade, so a first-frame stall there is painted at
                                near-zero opacity.
           Measured before: .search-open and the panel's first laid-out frame on the SAME frame (23.3ms
           against a ~6ms cadence), results at +30ms (19.7ms), six frames >10ms inside the first 300ms.
           The easing above is still doing its job and must not be re-front-loaded — the two fixes are
           complementary, not alternatives. MudPopover Delay=220/Duration=200 and the G6 warm/cold
           panelEnterDelay logic are deliberately UNCHANGED by S7-06; re-run the per-frame capture
           before trimming either. */
        /* S7-06: these four are now ALIASES of the canonical motion primitives in
           rently-dashboard-tokens.css. The names stay because the whole morph below reads them, and
           the fallbacks keep this sheet self-sufficient if it is ever loaded without the token sheet.
           --search-ease-out has no canonical twin — it is Material's standard curve, used only here —
           so it stays a literal. */
        --search-ease-in: var(--rently-ease-fuse, cubic-bezier(0.65, 0, 0.35, 1));  /* fuse: slow start, decisive, settles */
        --search-ease-out: cubic-bezier(0.4, 0.0, 0.2, 1);   /* split: standard */
        --search-dur-in: var(--rently-dur-emphasized, 260ms);
        --search-dur-out: var(--rently-dur-base, 200ms);
        /* Retained alias: several rules outside the morph (result rows, chips) still use it. Points at
           the EXIT pair, which is the base-state timing those rules always had. */
        --search-transition: var(--search-dur-out) var(--search-ease-out);

        --search-border-radius: 8px;
        --search-field-font-size: 0.9375rem;
        --search-shadow: 0 2px 8px rgba(0,0,0,0.1);
        --search-shadow-hover: 0 4px 16px rgba(0,0,0,0.15);

        /* The Search button's resting width. It is LOAD-BEARING, not documentation: the closed
           flex-basis of the search chip is computed from it, so the two must not drift apart.
           .search-button pins itself to this same token (flex: 0 0) rather than relying on
           min-width + content, so the basis math is exact at every viewport. */
        --search-btn-width: 100px;

        /* ══ G6 (2026-07-23) — the OPEN-state tray inset ═════════════════════════════════════════════
           Applied as PADDING on .search-bar-stack, never as margins on the children, and that choice
           is load-bearing in three separate ways:

             1. It is SYMMETRIC by construction. The G5 open state gave the two chips `margin: 3px 2px`
                and the Search button NOTHING, so the near-white tray leaked as a 2px sliver on the
                button's LEFT EDGE ONLY — the "white border around the Search button". Padding cannot
                produce that asymmetry: every flex item is inset by the same amount on all four sides.
             2. It fixes a 3px vertical OVERFLOW for free. The chips are `height: 100%` of a 40px bar,
                so a 40px content box plus 3px block margins made a 46px margin box centred in a 40px
                line — the raised active tab card physically poked out of the bar, top and bottom. With
                box-sizing: border-box, padding shrinks the CONTENT box to 34px and `height: 100%`
                resolves inside the bar instead.
             3. flex-basis percentages resolve against the flex container's CONTENT box, so the inset
                becomes structural: `100%` automatically means "the tray's interior" and the closed
                basis formula at .search-input-section needs no change at all.

           It is also the single knob for the tab height: 3px -> 34px tabs, 2px -> 36px. */
        --search-open-inset: 2px;

        /* The 2px outline shared by the fused bar and the dropdown panel so the two read as ONE
           object. Deliberately --rently-primary and NOT --section-accent: the panel is portalled into
           MudPopoverProvider at the document root, OUTSIDE the shell that carries --section-accent
           (see the note at the top of this file), so an accent-driven ring could never match the
           panel's border. OPAQUE by design too — the bar composites it over --rently-subtle-bg and
           the panel over the page, so a translucent mix would render as two different teals. Both
           inputs are tokens, so the C4 palette engine reprojects it correctly on dark. */
        --search-ring: color-mix(in srgb, var(--rently-primary) 40%, var(--rently-card-bg));

        /* ══ G7 (2026-07-23) — the ALIGNMENT RAIL ═════════════════════════════════════════════════════
           The complaint was "the popups need to line up with the input sections", and the reason they
           did not is that the panel's gutter was an unrelated round number (16px) while the bar's
           content starts wherever the tray inset plus the chip's own padding happens to land.

           This is that number, derived rather than guessed: the ACTIVE TAB's content-box left edge =
           the stack's padding (--search-open-inset) + the chip's padding-left (14px, see
           .search-input-section). Every panel gutter, every full-bleed rule and both footers read it,
           so panel content starts on exactly the same vertical as the tab's magnifier icon — in BOTH
           views. Change the chip padding and this follows it.

           NOTE it resolves against the :root value of --search-open-inset (3px), NOT the 0px that
           .search-bar-stack re-points it to while closed. That is correct: the panel only exists in
           the open state, where the inset IS 3px. */
        --search-panel-gutter: calc(var(--search-open-inset) + 14px);   /* 17px */

        /* The location view remains an intentional two-column map/address composition even though
           the trigger bar now has three equal fields. This token belongs to the panel's internal
           layout; it is not coupled to a trigger-tab boundary. */
        --search-panel-half: 50%;
    }

    /* Desktop Styles */
    /* Initiative C · C2 Pt3.C — the desktop SearchNav MudAppBar surface (replaces the old inline teal
       background on SearchNav.razor). Tinted Glass + Blend-gradient seam (no bottom border → blends into
       the hero below). Falls back to brand teal on the storefront (no --section-accent ancestor). */
    .search-nav-appbar {
        background: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 16%, rgba(255, 255, 255, 0.70));
        /* S7-06 verdict — KEEP, STATIC. A backdrop-filter is expensive (it resamples everything behind
           the bar), so it is a fair candidate for removal during the morph. It stays because it is not
           transitioned: it is a constant cost per composited frame, identical open, closed and
           mid-morph. Toggling or transitioning it to save that cost is the worse trade — the glass
           visibly pops on and off against the hero, right where the eye already is during the fuse. */
        -webkit-backdrop-filter: blur(12px);
        backdrop-filter: blur(12px);
    }

    .search-bar-wrapper {
        width: var(--rently-layout-max-width, 1440px);
        margin: 0 auto;
        display: flex;
        align-items: center;
    }

    .search-container {
        width: 100%;
    }

    /* ══ G4 (2026-07-22) — SPLIT search bar ══════════════════════════════════════════════════════════
       The three elements used to be fused by THIS rule alone: the stack owned the background, shadow,
       radius and `overflow: hidden`, while the children had no surface of their own. Splitting them is
       therefore SUBTRACTIVE — the surface moves down onto each child (below) and a gap separates them,
       matching the lab mock's .tnx-nav__search / .tnx-nav__loc / .tnx-nav__search-btn.

       The OPEN state re-fuses them by collapsing that gap to 0. `gap` is an interpolable length, so the
       three chips physically slide together into the single full-width bar that meets the dropdown —
       no new state, no JS: still driven entirely by the existing .search-open class.

       The !important on `gap` is REQUIRED and was QA-proven, not defensive. MudStack emits `gap-0`
       from Spacing="0", and MudBlazor's own `.gap-0 { gap: 0 }` carries no !important — so far so
       good. But BOOTSTRAP is also loaded (App.razor:113, before this sheet) and ships a utility of
       the SAME NAME as `.gap-0 { gap: 0 !important }`. Two libraries, one class name, and the
       important one wins at equal specificity regardless of source order. Without this the chips
       render flush and the split silently collapses — the tell is that --search-gap resolves
       correctly while `gap` computes to 0px.
       Only the base declaration needs it: the open state re-points --search-gap and flows through
       this same declaration, so it inherits the priority. */
    .search-bar-stack {
        /* --rently-space-4 is 0.75rem/12px on this scale — the same token the mock's
           .tnx-nav__inner--search uses for exactly this gap. Fallback matches it. */
        --search-gap: var(--rently-space-4, 12px);
        /* G6: CLOSED = flush. The three chips carry their own borders when split, so a tray inset
           there would just push them inward for no reason. .search-open re-points this to 3px and the
           padding animates, which is what turns the split bar into a tray. */
        --search-open-inset: 0px;
        /* G5: the CLOSED (exit) timing. Inherited by the chips, divider and button, so every
           transition shorthand in the morph picks up the right direction with no duplication. */
        --search-dur: var(--search-dur-out);
        --search-ease: var(--search-ease-out);
        gap: var(--search-gap) !important;
        /* G6: EXPLICIT, not inherited-and-hoped-for. The compact 48px-bar / 44px-tab contract depends on
           padding shrinking the content box rather than growing the border box. MudBlazor ships a
           global `*{box-sizing:border-box}`, but this rule is the one that would silently produce a
           56px bar if that ever changed, so it states the dependency locally. */
        box-sizing: border-box;
        /* G6: the containing block for the per-tab accent indicators (::after on each chip). */
        position: relative;
        padding: var(--search-open-inset);
        background-color: transparent;
        box-shadow: none;
        height: 48px;
        border-radius: var(--search-border-radius);
        overflow: visible;   /* was hidden — it would clip the per-chip radii and shadows */
        /* Narrowed from `all`: animating every property also animated colour/shadow changes that used
           to be instant, and `all` would now include the flex-basis swap on every unrelated repaint.
           G6 EXTENDS this list with `padding` — it does NOT restate it on .search-open. Restating a
           transition shorthand on a state class replaces the whole list rather than adding to it, and
           that is precisely the mistake documented at .tab-inactive below (the ~348px lurch). */
        /* S7-06 verdict — KEEP, deliberately and in full. gap + padding are layout properties and a
           transform-based (FLIP) rewrite would take them off the layout path, but this list IS the
           fuse morph the design brief calls out as working well. The measured jank was never this
           transition: it was DOM mounting inside its frames, which the quiet window now moves out.
           Do not "optimise" this list without re-running the per-frame capture first. */
        transition: gap var(--search-dur) var(--search-ease),
                    padding var(--search-dur) var(--search-ease),
                    background-color var(--search-dur) var(--search-ease),
                    box-shadow var(--search-dur) var(--search-ease),
                    border-radius var(--search-dur) var(--search-ease);
        width: 100%;
        align-items: center;
    }

        .search-bar-stack.search-open {
            --search-gap: 0px;
            --search-open-inset: 3px;
            /* G5: the OPEN (enter) timing — longer, and on a curve that settles rather than coasting.
               Declared here so it is the destination style when the class lands. */
            --search-dur: var(--search-dur-in);
            --search-ease: var(--search-ease-in);
            /* G5: the shared open width of BOTH chips, resolved once here and inherited by them, so
               the two can never drift apart by a rounding difference.
               G6 re-derived it for the tray. `100%` is now the PADDED CONTENT box, so the inset is
               already excluded from the numerator and only three things remain to subtract:
                 - the Search button          --search-btn-width
                 - the 1px fused divider      1px
                 - the button's leading gap   --search-open-inset
               The old `9px` term (8px of chip margins + 1px divider) is RETIRED along with the margins
               it accounted for. If you re-add a margin anywhere in this bar, this formula is what
               breaks — silently, as a half-pixel asymmetry between the two tabs. */
            --search-third: calc((100% - var(--search-btn-width) - 2px - var(--search-open-inset)) / 3);
            border-radius: var(--search-border-radius) var(--search-border-radius) 0 0;
            /* G5: a THREE-SIDED ring (top + both sides), not a `0 0 0 2px` spread.
               A spread ring also paints across the BOTTOM edge — drawing a hairline seam exactly where
               the dropdown panel welds on. Offset copies leave the bottom edge clean while the two
               lateral copies run the full height, so they meet the panel's own side borders and the
               pair reads as one continuously outlined object. --search-ring is brand teal rather than
               --section-accent because the portalled panel cannot resolve the accent (see :root).

               G6: FIVE copies, not three. An offset-copy ring is the UNION of translated silhouettes,
               and at a rounded corner the union of "shifted up" and "shifted left" does not cover the
               2px band around the 45° arc — it left a ~1px notch at each of the two 8px top corners,
               visible as a nick in the outline at exactly the place the eye checks it. The two
               diagonal copies fill the arcs. Bottom edge still untouched. */
            box-shadow: 0 -2px 0 0 var(--search-ring),
                        -2px 0 0 0 var(--search-ring),
                         2px 0 0 0 var(--search-ring),
                        -2px -2px 0 0 var(--search-ring),
                         2px -2px 0 0 var(--search-ring);
            /* was a hardcoded #e4e4e4, which stayed light grey under [data-theme=dark] */
            background-color: var(--rently-subtle-bg, #f5f7f8);
        }

    /* Search Icon — spacing now comes from the chip's own padding + gap (it used to need its own 12px
       margins as a direct child of the fused stack). Accent-text ink per the mock. */
    .search-icon {
        margin: 0;
        flex-shrink: 0;
        color: var(--section-accent-text, var(--rently-primary-dark));
    }

    /* ── The three field chips: each carries its own surface while closed ── */
    /* ══ G5 (2026-07-22) — why the widths are written THIS way ═══════════════════════════════════════
       The G4 morph animated `flex-basis` and `max-width` between `auto`/`none` (closed) and `50%`
       (open). Those are KEYWORDS: CSS cannot interpolate a keyword to a length, so both properties
       fell back to DISCRETE interpolation and flipped at exactly 50% of the duration. The location
       chip (320px -> 50%, length -> percentage) meanwhile animated perfectly smoothly.

       The visible symptom was a lurching Search button. At the halfway frame on a 1440px bar the
       location chip had glided to ~520px while the search chip was still free-space-sized at ~808px;
       then its basis AND max-width snapped to 720px on the same frame, leaving ~100px of unclaimed
       free space that flexbox parks at the END of the line — so the button jumped ~100px left and
       drifted back right over the remaining 150ms.

       Three rules follow from that, and all three matter:
         1. flex-basis carries a real <length-percentage> calc() in BOTH states, so it interpolates
            component-wise (percentage part and length part independently) at every frame.
         2. max-width is CONSTANT (`none`) and no longer animated at all — it was only ever a second,
            redundant expression of the width, and it was the other half of the snap.
         3. flex-grow / flex-shrink are CONSTANT across both states. Changing a flex factor mid-morph
            re-distributes free space on a single frame, which is a layout discontinuity no easing can
            hide. Only flex-basis moves; the factors just stay put.
       `margin` is now in the transition list too — the open state adds `3px 2px`, which used to
       appear instantly and jog the whole bar 2px sideways at t=0. */
    .search-input-section,
    .location-picker-section,
    .date-picker-section {
        display: flex;
        align-items: center;
        min-width: 0;
        height: 100%;
        padding: 0 14px;   /* mock */
        gap: 8px;          /* mock */
        margin: 0;         /* G5: explicit — the open state animates this to 3px 2px */
        background-color: var(--rently-card-bg);
        border: 1px solid var(--rently-border);
        border-radius: var(--search-border-radius);
        box-shadow: var(--search-shadow);
        /* CONSTANT in both states — see rule 3 above. flex-shrink stays 1 purely as an overflow
           safety valve; with the exact bases below the line never overflows, so it never fires. */
        flex-grow: 0;
        flex-shrink: 1;
        max-width: none;
        /* S7-06 verdict — KEEP. flex-basis + margin are exactly the two chip properties that make the
           split bar fuse into one pill, i.e. the animation this session was asked to preserve. The
           baseline capture recorded 34 distinct interpolated chip widths, so the interpolation itself
           is healthy; the long frames sat on the DOM-mount work sharing those frames, not here. */
        transition: flex-basis var(--search-dur) var(--search-ease),
                    margin var(--search-dur) var(--search-ease),
                    border-radius var(--search-dur) var(--search-ease),
                    border-color var(--search-dur) var(--search-ease),
                    box-shadow var(--search-dur) var(--search-ease),
                    background-color 0.2s ease;
    }

    /* The three closed field chips share the available width exactly. Two zero-width divider items
       each cancel their own leading gap below, leaving three real gaps: field/field/field/button. */
    .search-input-section,
    .location-picker-section,
    .date-picker-section {
        flex-basis: calc((100% - var(--search-btn-width) - 3 * var(--search-gap)) / 3);
    }

    /* Long addresses ellipsis inside the locked chip rather than widening it and reflowing the bar.
       `display: block` is REQUIRED, not cosmetic: MudText renders .address-text as a SPAN, and
       overflow/text-overflow have no effect on an inline non-replaced element — the span laid out at
       its full 370px and got hard-clipped by .address-display's overflow with no ellipsis at all
       (QA-caught 2026-07-22). min-width:0 lets it actually shrink inside the flex chip. */
    .location-picker-section .search-location-input input,
    .location-picker-section .mud-typography {
        display: block;
        min-width: 0;
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* RentlyAddressPicker renders its OWN bordered white trigger (.address-picker-input: 1px #e0e0e0,
       4px radius, white fill). While the bar was one fused pill that read as an inner field; now that
       the location chip has its own border and card, it would be a second frame nested inside the
       first. The chip IS the frame — strip the picker's inside the nav only.

       Note the .search-nav-appbar prefix: the picker's rules live in an inline <style> in its own
       markup, which is later in DOCUMENT order than this head-loaded sheet, so it wins every
       equal-specificity tie — including [data-theme="dark"] .address-picker-input at (0,2,0). These
       are (0,3,0) so they win outright in both themes rather than by load order. */
    .search-nav-appbar .location-picker-section .address-picker-container,
    .search-nav-appbar .location-picker-section .address-picker-input {
        width: 100%;
    }

    /* G6 (2026-07-23): the chip is a <button> now, and the picker it contains renders its OWN clickable
       trigger with its OWN @onclick -> OnInputClicked -> OpenLocationTab. A click would therefore fire
       OpenLocationTab twice (once on the picker, once as it bubbles to the button), running the focus
       move and the scroll reset on both. Making the picker inert to the pointer lets every click land
       on the button instead — the picker is purely a display surface here; the chip owns the behaviour.
       Keyboard is unaffected: the button handles Enter/Space/Escape itself. */
    .search-nav-appbar .location-picker-section .address-picker-container {
        pointer-events: none;
    }

    .search-nav-appbar .location-picker-section .address-picker-input,
    .search-nav-appbar .location-picker-section .address-picker-input:hover,
    .search-nav-appbar .location-picker-section .address-picker-input.picker-open {
        border: 0;
        border-radius: 0;
        padding: 0;
        background-color: transparent;
        box-shadow: none;
        /* G5: RentlyAddressPicker's own inline sheet declares `transition: all 0.2s ease` on this
           element. `all` means it re-animates every property the chip's morph pushes through it —
           padding, border, effective width — on a SECOND timeline (0.2s ease) fighting the chip's
           220ms settle curve. Narrow it to the one property that actually needs to move here; the
           chip above owns every geometry transition. */
        transition: background-color var(--search-dur) var(--search-ease);
    }

    /* Hover elevation moved off the (now transparent) stack and onto the chips — on the stack it would
       have drawn a shadow rectangle around the three separated elements. */
    .search-bar-stack:not(.search-open) .search-input-section:hover,
    .search-bar-stack:not(.search-open) .location-picker-section:hover,
    .search-bar-stack:not(.search-open) .date-picker-section:hover {
        box-shadow: var(--search-shadow-hover);
        border-color: var(--rently-border-strong);
    }

    /* G6 (2026-07-23) — the second reduced-motion block that used to sit here is GONE. Its
       `.search-popover` !important rule (MudBlazor's Delay/Duration render as INLINE longhands, so a
       stylesheet rule cannot beat them otherwise) has moved into the single consolidated block at the
       END of this file. Two reduced-motion blocks in one section was itself the bug: each silently
       missed everything declared below it, and having two made it impossible to tell which one a new
       selector belonged in. There is now exactly ONE, and it is last. */

    /* The three desktop field labels meet at 15px: halfway between the former 14px query
       and 16px location/date labels, without increasing the compact 48px shell. */
    .search-input,
    .location-picker-section .mud-typography,
    .date-picker-label,
    .tablet-search-label {
        font-size: var(--search-field-font-size);
        font-weight: 400;
        line-height: 1.5;
    }

    /* Suppress Radzen's inner focus paint in every state. Otherwise its blue box flashes before
       .tab-active lands during the morph and returns after focus restoration on close. The field
       chip remains the interaction boundary and owns the accessible focus treatment below. */
    .search-input-section .rz-textbox,
    .search-input-section .rz-textbox:focus,
    .search-input-section .rz-textbox:focus-visible,
    .search-input-section .rz-textbox:focus-within,
    .search-input-section input {
        outline: none !important;
        box-shadow: none !important;
        border-color: transparent !important;
    }

    /* G7: was a hardcoded #727272 — 4.81:1 on white, i.e. passing SC 1.4.3 with 7% of headroom on a
       literal that nothing re-derives. --rently-text-tertiary (#64748b) is ~5.0:1 and comes from the
       token layer, so both themes now resolve from the same place (the dark override further down
       already did). */
    .search-input input::placeholder,
    .search-location-input input::placeholder {
        color: var(--rently-text-tertiary) !important;
    }

    /* Search Divider — G4: exists only in the OPEN (fused) state; while the bar is split the chip
       borders already separate the fields. The visible line is a 1px border-RIGHT on a zero-width
       <hr>, so `width` is not animatable in any useful sense — collapse border-right-width instead. */
    .search-divider {
        margin: 8px 0;
        /* The divider is still a flex ITEM even when collapsed to zero width, so it collects a gap on
           BOTH sides — the two fields would sit 2x--search-gap apart while the button sits 1x away.
           Pulling the divider back by one gap restores an even rhythm across all three chips.
           Self-neutralising: --search-gap is 0 in the open state, so this resolves to 0 there. */
        margin-inline-start: calc(var(--search-gap, 0px) * -1);
        opacity: 0;
        border-right-width: 0;
        /* G5: pinned. As a zero-width flex item it was eligible for shrinking, which would have eaten
           the 1px line the open state grows — and its 1px is part of the --search-half math. */
        flex-shrink: 0;
        /* S7-06 verdict — border-right-width DROPPED from the list, the other two KEPT.
           Dropping it: it is a layout property animating on every open, and animating it buys nothing
           visible. The line is simultaneously fading 0 -> 0.3 opacity, and a 1px rule at opacity 0 is
           invisible whatever its width, so snapping the width to its final 1px on frame 0 is
           visually identical and takes one relayout-per-frame out of the morph's critical path.
           Keeping margin-inline-start: it is NOT cosmetic. It cancels the double gap the divider
           collects as a zero-width flex item (see the note above), and --search-gap is itself
           animating 8px -> 0 across the same 260ms. Snap the margin and the divider lurches 8px on
           frame 0 while every sibling glides. It has to track the gap it neutralises.
           Keeping opacity: compositable, and it IS the reveal. */
        transition: opacity var(--search-dur) var(--search-ease),
                    margin-inline-start var(--search-dur) var(--search-ease);
    }

    .search-bar-stack.search-open .search-divider {
        opacity: 0.3;
        border-right-width: 1px;
    }

    /* Search Button — G4: its own fully-rounded chip when split; squares off its inner corners to
       rejoin the bar when open. font-weight stays 500: the D32 dark-mode AA note below is written
       against that value, and the mock's 700 is not what changes the layout. */
    .search-button {
        height: 100%;
        border-radius: var(--search-border-radius);
        /* G5: pinned to the token rather than sized by min-width + content. The search chip's closed
           flex-basis subtracts exactly --search-btn-width, so if the button could size itself (a
           longer label, a different font metric) the basis math would drift and the morph would end
           on a fractional mismatch. min-width stays as a floor for the same value. */
        flex: 0 0 var(--search-btn-width);
        min-width: var(--search-btn-width);
        /* G6: explicit 0 so the open state has a value to animate FROM. The stack's padding handles
           the button's outer three sides; only the gap between it and the location tab is its own. */
        margin-inline-start: 0;
        padding: 0 22px;   /* mock */
        text-transform: none;
        font-weight: 500;
        box-shadow: var(--search-shadow);
        /* S7-06 verdict — KEEP. margin-inline-start is a layout property, but it is how the button
           travels into the tray as the bar fuses; snapping it would leave the button behind while the
           chips glide. Same reasoning as the chips' flex-basis below. */
        transition: border-radius var(--search-dur) var(--search-ease),
                    margin-inline-start var(--search-dur) var(--search-ease),
                    box-shadow var(--search-dur) var(--search-ease),
                    background-color var(--search-dur) var(--search-ease);
        color: white !important;
        background-color: var(--rently-secondary) !important;
    }

    .search-bar-stack.search-open .search-button {
        /* G6: was `0 var(--search-border-radius) 0 0` — square left corners made sense when the button
           was welded flush to the bar's edge and shared its top-right corner. Inside a tray it is a
           control like the two tabs, so it takes the same 6px they do. A half-squared chip floating on
           a near-white tray read as a rendering fault. */
        border-radius: var(--rently-radius-sm, 6px);
        box-shadow: none;
        /* The ONLY inset the button owns. The other three sides come from the stack's padding, which
           is exactly what makes the four gaps around it equal. */
        margin-inline-start: var(--search-open-inset);
    }

    .search-button:hover {
        background-color: #d63621 !important; /* C4: converge to the secondary-red ramp */
    }

    /* D32 — search-button dark-mode AA (2026-07-06). White "Search" (14px/500 = normal text, 4.5:1 bar)
       on the reprojected dark --rently-secondary (#f4604f, C4 engine live-reprojects to ~#f25f4e)
       composites to 3.17-3.22:1 (SC 1.4.3 FAIL). Darken the fill to on-brand deeper reds so white text
       clears AA. :not(:disabled) keeps Mud's :disabled grey on the transient searching state in BOTH
       modes (our (0,2,0)! would otherwise tie .mud-button-filled:disabled and, by load order, paint red
       on the dark disabled button only). Literals, not var(): the C4 engine reprojects tokens, never
       literals (the D29/D30/D31 reproject-trap pattern; mirrors the base :hover #d63621 literal above).
       Light byte-identical (dark-scoped); the light-mode white-on-#EF412c 3.84:1 on FILLED buttons was
       remediated 2026-07-24 (Session-5 H8: .mud-button-filled-secondary re-points the Mud palette vars
       to --rently-secondary-filled #d63a26, 4.67:1 — rently-dashboard-tokens.css). Text/outlined
       secondary (red-on-white) remains the tracked GlobalCssDarkAuditSweep.md section-7 residual. */
    [data-theme="dark"] .search-button:not(:disabled)       { background-color: #c0281a !important; } /* white 5.90:1 */
    [data-theme="dark"] .search-button:not(:disabled):hover { background-color: #a81e11 !important; } /* white 7.35:1 */

    /* Search Popover */
    /* ══ G5 (2026-07-22) — two-beat choreography, and the trap it opens ══════════════════════════════
       The panel used to fade in the instant the bar started morphing, so for ~300ms a full-width
       dropdown sat welded to a bar that had not finished fusing. It now waits: MudPopover Delay="220"
       + Duration="200" in SearchNav.razor means the bar fuses first (0-260ms) and the panel unfurls
       beneath it (220-420ms). Those are real 9.7 parameters — they render as inline transition-delay
       and transition-duration LONGHANDS on the popover element.

       The trap: during that 220ms delay the element already carries .mud-popover-open, so MudBlazor's
       `:not(.mud-popover-open){pointer-events:none}` has stopped applying — but opacity is still 0.
       An invisible, full-width, full-height panel would sit over the page swallowing clicks and
       hovers for 180ms. `visibility` fixes it: it interpolates DISCRETELY, so it flips to visible only
       when the transition actually begins (i.e. after the delay elapses), and visibility:hidden blocks
       pointer events in the meantime.

       Widening transition-property from this sheet is safe precisely because MudBlazor sets only the
       duration/delay LONGHANDS inline — both entries in the list inherit the same 200ms/180ms. On
       close, MudBlazor's `:not(.mud-popover-open)` forces 0ms on duration AND delay with !important,
       so the panel (and this visibility flip) drop instantly. That is also why the closing order is
       panel-first-then-bar: 9.7 cannot fade a popover out at all. */
    .search-popover {
        margin-top: 0;
        visibility: hidden;
    }

    .search-popover.mud-popover-open {
        visibility: visible;
        transition-property: opacity, visibility;
    }

    /* The scrim's fade is a keyframe animation (mud-animation-fadein ease .15s), not a transition, so
       it cannot be retimed by a parameter — MudOverlay has no Duration/Transition in 9.7. Stretch it
       to match the 220ms bar fuse so the dim and the morph land together instead of the dim racing
       ahead. This sheet loads after MudBlazor.min.css, so equal specificity is enough. */
    .z-index-search-modal .mud-overlay-scrim {
        animation-duration: 220ms;
    }

    /* ── OPEN state: the chips give up their individual identity and re-fuse into one bar ──
       G4: geometry only. Each chip drops its own border/shadow and all three take equal thirds, so the
       group reads as the single full-width surface that the dropdown panel meets — the width the
       dropdown has always had. The raised-active-card UX inside it is unchanged (below).
       These are (0,3,0) so they beat the (0,2,0) closed-width rules above regardless of order.

       G5: this is now a pure flex-BASIS swap. The old `flex: 1 1 50%; max-width: 50%` shorthand also
       rewrote flex-grow/flex-shrink and animated a keyword max-width — the two halves of the snap
       diagnosed on the base rule above. --search-third is inherited from .search-open so all chips
       resolve the identical value, and `margin` is now transitioned rather than applied instantly. */
    .search-bar-stack.search-open .search-input-section,
    .search-bar-stack.search-open .location-picker-section,
    .search-bar-stack.search-open .date-picker-section {
        flex-basis: var(--search-third);
        border-color: transparent;
        box-shadow: none;
        /* G6: `margin: 3px 2px` DELETED. The stack's padding is the inset now — see
           --search-open-inset. Keeping this would double the horizontal inset AND re-open the
           asymmetry it was half-causing (the button never had a matching margin, which is what
           produced the white sliver on its left edge). It also re-broke the vertical fit: a 40px
           `height:100%` chip plus 3px block margins overflowed the 40px bar.
           `margin` deliberately STAYS in the base transition list — it is inert now, but restating a
           transition shorthand on a state class is what caused the ~348px lurch (see .tab-inactive). */
        /* Containing block for the accent tab indicator below. .tab-active already sets this; the
           inactive half needs it too, or its ::after would anchor to .search-bar-stack and both
           indicators would stack on top of each other at the bar's left edge. */
        position: relative;
    }

    /* Tab-like section styling when dropdown is open.
       NOTE the .search-bar-stack.search-open prefix: it is required, not decorative. The fuse rule
       above sets `box-shadow: none` at (0,3,0); without this prefix these would be (0,2,0) and the
       active half would silently lose its raised card. */
    /* ══ G7 (2026-07-23) — the active half is now a REAL TAB, welded to the panel ════════════════════
       Three changes, and each one answers a specific complaint:

       1. `border-radius: 6px 6px 0 0`. A fully-rounded card floating on a tray is a chip; a card with
          square bottom corners is a tab. This is what makes "toggling between two tabs in the popup"
          legible as a metaphor rather than as two highlighted fields.

       2. The card grows DOWN through the tray's 3px padding so its bottom edge lands exactly on the
          bar's border box, which is where the panel welds. Previously it stopped 3px short and the
          tray showed as a sliver between the "active" field and the panel it was supposedly part of.

          THIS TAKES THREE DECLARATIONS, NOT ONE, and the reason is worth writing down. The negative
          `margin-block-end` alone is NOT enough: .search-bar-stack is `align-items: center`, and
          centring positions the item's MARGIN box. A -3px block-end margin shrinks the margin box to
          31px, which centring then parks 1.5px down inside the 34px line — so the active tab came
          out 1.5px LOWER than its sibling and still ended 1.5px SHORT of the weld. QA measured
          exactly that: sibling bottom 124.0, active bottom 125.5, bar bottom 127.0.

          `align-self: stretch` + `height: auto` makes the MARGIN box fill the line instead (34px),
          so the border box is 34 + 3 = 37px: top flush with the inactive tab, bottom flush with the
          bar's border box, which is the panel's top edge. Exactly the weld.

          Still margin rather than a height change, because `margin` is already in the base transition
          list (see .search-input-section) so the growth animates for free. `height: auto` is a
          discrete flip but a harmless one — at t=0 stretch resolves to the same 34px that
          `height: 100%` was already producing, so nothing jumps. `.search-bar-stack` is already
          `overflow: visible`, so the 3px overhang paints rather than being clipped. And block-axis
          margins on a row flex item do not affect main-axis sizing, so --search-half is untouched.

       3. A 1px accent border on the three non-welded sides. THIS IS THE "ACTIVE OUTLINE" THE USER
          ASKED FOR ON BOTH FIELDS. It replaces the old arrangement where the search chip carried a
          permanent :focus-within ring (the input holds DOM focus the whole time the panel is open,
          so it never turned off) and the location chip carried a :focus-visible ring that Chrome
          never grants on a mouse click (so it never turned on). Driving it off .tab-active makes it a
          STATE, which is what it always meant — and both tabs get it identically.

       It is also the SC 1.4.11 fix. Measured, on the three surface modes:
           light tray  #256f7a on #f8f9fb = 5.49:1     dark tray  #74d0dc on #334155 = 5.82:1
           light card  #256f7a on #ffffff = 5.78:1     dark card  #74d0dc on #1e293b = 8.22:1
       and on [data-search-nav-surface="solid"], where the tray and the card are BOTH
       --rently-card-bg (1.00:1 — the card is literally invisible), the border and the weld bar are
       the only state signals that exist. Brand #35a0ae is NOT usable here: 2.94:1 on the tray.

       Bonus: `border` is the one channel that survives `forced-colors: active`. background-color and
       box-shadow are both dropped there, so before this rule the active tab was completely
       indistinguishable in Windows High Contrast.

       DO NOT add a `transition:` declaration to this rule. border-color, border-radius, margin and
       box-shadow are all already in the base list; restating the shorthand on a state class REPLACES
       that list, which is the ~348px lurch documented at .tab-inactive below. */
    .search-bar-stack.search-open .search-input-section.tab-active,
    .search-bar-stack.search-open .location-picker-section.tab-active,
    .search-bar-stack.search-open .date-picker-section.tab-active {
        background-color: var(--rently-card-bg); /* C5 Pt3c.C: token-swap (light #fff, flips slate on dark) */
        border-radius: 6px 6px 0 0;
        /* The three-declaration weld — see item 2 above. Order matters only for readability. */
        align-self: stretch;
        height: auto;
        margin-block-end: calc(-1 * var(--search-open-inset));
        border: 1px solid var(--rently-primary-dark);
        border-bottom: 0;
        box-shadow: 0 1px 6px rgba(0,0,0,0.12);
        position: relative;
        z-index: 1;
    }

    /* Literal, for the same reason as the weld bar below: the C4 palette engine live-reprojects
       --rently-primary-dark back to the mid-tone brand #35a0ae under [data-theme=dark]. */
    [data-theme="dark"] .search-bar-stack.search-open .search-input-section.tab-active,
    [data-theme="dark"] .search-bar-stack.search-open .location-picker-section.tab-active,
    [data-theme="dark"] .search-bar-stack.search-open .date-picker-section.tab-active {
        border-color: #74d0dc;
    }

    /* G5: the `transition: background-color 0.2s ease` that used to be in this rule is DELETED, and
       that deletion is the single most important line of this pass.

       `transition` is a SHORTHAND, so it did not add background-color to the list — it REPLACED the
       whole list, discarding the flex-basis entry the base rule sets. Whichever chip is inactive when
       the bar opens therefore had no width transition at all. Because the bar always opens on the
       Search tab, that was always the LOCATION chip: its basis jumped straight to its final value on
       frame one while the search chip (tab-active, whose rule never touches `transition`) glided.
       Flexbox then redistributed the line around the mismatch, which is what produced the ~348px
       first-frame lurch. The tell was a computed flex-basis of calc(50% - 54.5px) on the very first
       painted frame, next to an untouched calc(100% - 444px) on its sibling.

       Nothing needs to be re-added: the base rule's list already ends with `background-color 0.2s
       ease`, which is exactly what this rule was trying to express. If a future rule here needs its
       own timing, extend the base list — never restate `transition` on a state class. */
    .search-bar-stack.search-open .search-input-section.tab-inactive,
    .search-bar-stack.search-open .location-picker-section.tab-inactive,
    .search-bar-stack.search-open .date-picker-section.tab-inactive {
        background-color: transparent;
        cursor: pointer;
        border-radius: 6px;
    }

        .search-bar-stack.search-open .search-input-section.tab-inactive:hover,
        .search-bar-stack.search-open .location-picker-section.tab-inactive:hover,
        .search-bar-stack.search-open .date-picker-section.tab-inactive:hover {
            /* G6: was rgba(255,255,255,0.45) — a hardcoded white film that measured ~1.02:1 against the
               #f8f9fb tray (i.e. invisible) and needed a separate dark-mode override to not flash light
               on a dark bar. This is the wash every other nav list already uses: .menu-item,
               .search-result-item, .address-item. One hover vocabulary, both themes, no override. */
            background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 8%, transparent);
        }

    /* ══ G6 (2026-07-23) — the ACTIVE-TAB indicator ══════════════════════════════════════════════════
       This is an SC 1.4.11 (Non-text Contrast, AA) obligation, not a decorative flourish. The state
       signal before this rule was "white card vs transparent on a near-white tray", measured:

           light   #ffffff card on #f8f9fb tray   = 1.05 : 1     FAIL (3:1 required)
           dark    #1e293b card on #334155 tray   = 1.41 : 1     FAIL
           solid   card on card                   = 1.00 : 1     FAIL — literally invisible, because
                                                                 [data-search-nav-surface="solid"]
                                                                 resolves BOTH to --rently-card-bg

       The 0 1px 6px rgba(0,0,0,.12) shadow does not rescue it: 1.39:1 is its theoretical peak at full
       alpha, and a 6px blur has no measurable boundary to test against in the first place.

       COLOUR CHOICE IS MEASURED, NOT AESTHETIC. Brand #35a0ae scores 2.94:1 on the #f8f9fb tray and
       FAILS — the accepted 3.09:1 SYS-07 figure is against PURE white, and this tray is not white.
       --rently-primary-dark #256f7a = 5.49:1 on the tray / 5.78:1 on the card. Dark mode uses the
       LITERAL #74d0dc (5.82:1 on #334155) because the C4 palette engine live-reprojects
       --rently-primary-dark back to #35a0ae under [data-theme=dark] — the same reproject trap that
       forced literals into .pill-collection and .search-result-pricing.

       Per-tab ::after, NOT one sliding bar on the stack: an absolutely-positioned `%` resolves against
       the PADDING box while flex-basis `%` resolves against the CONTENT box, so a stack-level slider
       would land up to 3px off on the location half. A pseudo-element is exact by construction, and
       because the two halves are adjacent the opacity+translateY crossfade still reads as a slide.

       G7 (2026-07-23) — the bar MOVES TO THE SEAM and runs the full width of the tab.

       It used to be `left: 14px; right: 14px; border-radius: 3px 3px 0 0`, which drew a floating
       lozenge inside the chip, 3px above the bar's real bottom edge. That reads as a decoration
       sitting in the tray. What it needs to read as is the weld between the tab and the panel — so it
       is now flush (`left: 0; right: 0`), square-ended, and `bottom: 0` follows the tab's border box
       down through the tray inset automatically now that .tab-active carries a negative block-end
       margin. Bar and panel meet on one line with nothing between them.

       COLOUR: --rently-primary-dark unconditionally, NOT --section-accent-text. The bar can resolve
       the section accent but the PANEL cannot — it is portalled to the document root, outside the
       shell that carries it, which is why .search-dropdown-paper's border reads --search-ring (brand
       teal). Preferring the accent here would weld an amber bar flush against a teal border under
       [data-section="learning"], with the colour change landing on the exact pixel the eye checks.
       Contrast is unaffected: the measured figures on .tab-active are already this pair.

       Per-tab ::after, NOT one sliding bar on the stack: an absolutely-positioned `%` resolves
       against the PADDING box while flex-basis `%` resolves against the CONTENT box, so a stack-level
       slider would land up to 3px off on the location half. A pseudo-element is exact by
       construction, and because the two halves are adjacent the opacity+translateY crossfade still
       reads as a slide.

       3px tall — a hairline gets lost against a 2px panel border. */
    .search-bar-stack.search-open .search-input-section::after,
    .search-bar-stack.search-open .location-picker-section::after,
    .search-bar-stack.search-open .date-picker-section::after {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        height: 3px;
        border-radius: 0;
        background-color: var(--rently-primary-dark);
        opacity: 0;
        transform: translateY(3px);
        pointer-events: none;
        z-index: 2;
        transition: opacity var(--search-dur) var(--search-ease),
                    transform var(--search-dur) var(--search-ease);
    }

    .search-bar-stack.search-open .search-input-section.tab-active::after,
    .search-bar-stack.search-open .location-picker-section.tab-active::after,
    .search-bar-stack.search-open .date-picker-section.tab-active::after {
        opacity: 1;
        transform: translateY(0);
    }

    /* Literal, not var() — see the reproject note above. */
    [data-theme="dark"] .search-bar-stack.search-open .search-input-section::after,
    [data-theme="dark"] .search-bar-stack.search-open .location-picker-section::after,
    [data-theme="dark"] .search-bar-stack.search-open .date-picker-section::after {
        background-color: #74d0dc;
    }

    /* ══ G7 (2026-07-23) — FOCUS, now that STATE owns the border ═════════════════════════════════════
       The indicator and the 1px border on .tab-active mark which view is SHOWING. These mark where
       the KEYBOARD is. They have to stay tellable apart, because a keyboard user must be able to see
       that the location tab is focused while the search view is still the active one (SC 2.4.7).

       WHAT CHANGED AND WHY. The old pair was:
           .search-input-section:focus-within   -> a 2px inset ring
           .location-picker-section:focus-visible -> a 2px outset ring
       and neither behaved as a focus indicator. The input holds DOM focus for the entire time the
       search view is open, so :focus-within was permanently true and its "focus" ring was really a
       state ring. The location chip is a <button>, and Chrome does not grant :focus-visible on a
       mouse click, so its ring never appeared at all for pointer users. That asymmetry is exactly
       what the user reported as "the address input doesn't get the same active outline". State moved
       to .tab-active; what is left here is focus, and only focus.

       THE SHAPE IS A DOUBLE LINE, and it is drawn with `outline` ALONE — no box-shadow ply.
       WCAG 2.1 sets no quantitative bar for 2.4.7, but if focus and state render as the same single
       accent line they are not meaningfully distinct. `outline-offset: -3px` puts the 2px ring three
       pixels inside the border box, so on an active tab the eye gets: 1px state border, 2px of card
       showing through, 2px focus ring. A double line, for free, out of geometry that already exists.

       A box-shadow ply was the first attempt and it was WRONG: `.search-bar-stack.search-open
       .{...}-section.tab-active` is (0,4,0) and sets its own box-shadow, so it would have silently
       clobbered a (0,3,0) focus shadow on exactly the tab that is focused most of the time. `outline`
       is a property .tab-active never touches, so there is no specificity fight to lose.

       BOTH RINGS ARE INSET. With --search-gap: 0 in the open state the two tabs are touching, so an
       outset ring on either one overlaps its neighbour. (That finding forced the search field's ring
       inset in G6; it now applies to the location chip too, because the chip finally has an inset it
       can hug.)

       :has(input:focus-visible) FIRST, :focus-within as the fallback. A <div> cannot itself match
       :focus-visible when its <input> child is focused, so :has is the precise selector; the fallback
       keeps a ring on engines that lag on :has. One of the two is mandatory, because
       .search-input-section.tab-active strips Radzen's own ring with `outline: none !important`
       further up — this container rule is the input's ONLY focus indicator.

       2026-07-23 — BOTH input arms are now gated :not(.tab-active), and the reason is a spec detail
       the paragraph above missed: EDITABLE TEXT FIELDS match :focus-visible whenever they hold focus,
       INCLUDING focus given by a mouse click. So :has(input:focus-visible) was never a keyboard-only
       path — while the search view is open the input holds DOM focus the whole time, both arms were
       permanently true, and this 2px ring stacked on .tab-active's 1px border as the "thick full
       border" the user reported (the double-line intent above only reads as designed when focus is
       somewhere it can LEAVE). The gate keys the ring off STATE instead of modality:
         · view active   -> no ring; the text caret + the .tab-active chrome are the focus indication
                            (a caret is a recognised SC 2.4.7 sufficient indicator for text fields);
         · bar closed    -> no .tab-active anywhere, so a focused input still gets the ring — the
                            closed/split bar keeps a visible indicator for BOTH modalities;
         · location chip -> untouched. It is a real <button>, :focus-visible is modality-correct
                            there, and it can be keyboard-focused while the SEARCH view is active —
                            in which case its ring is the one ring on screen, which is exactly the
                            "focus and state tellable apart" requirement this block exists for. */
    .search-bar-stack .search-input-section:has(input:focus-visible):not(.tab-active),
    .search-bar-stack .search-input-section:focus-within:not(.tab-active),
    .search-bar-stack .location-picker-section:focus-visible,
    .search-bar-stack .date-picker-section:focus-visible {
        outline: 2px solid var(--section-accent-text, var(--rently-primary-dark));
        outline-offset: -3px;
    }

    /* ══ LOCATION TAB — the embedded RentlyAddressPicker, NAV CONTEXT ONLY ═══════════════════════════
       G4 started this re-skin; G6 (2026-07-23) finishes it and re-scopes every rule.

       WHY NOT JUST EDIT THE PICKER'S OWN SHEET: RentlyAddressPicker.razor carries an UNSCOPED GLOBAL
       <style> block, and RentlyAddressPickerForm.razor — a DIFFERENT component, used by
       LocationWizardStep, ConfigureRentalTemplate, AgentApply and DisplayInfoConfiguration — declares
       its own global rules for the IDENTICAL class names (.picker-header, .picker-footer,
       .address-section, .address-list, .address-item, .address-item-content). Editing either sheet is
       a cross-component regression whose winner depends on which component happens to render later on
       a given page. So the re-skin lives here instead, and only ever applies inside the search panel.

       WHY THE .search-dropdown-paper PREFIX IS MANDATORY, not tidiness: the picker's own
       [data-theme="dark"] rules are (0,2,0) AND later in document order than this head-loaded sheet,
       so any (0,2,0) override here LOSES in dark mode. That was live: G4's
       `.location-tab-content .picker-footer { background: var(--rently-card-bg) }` was being defeated
       by `[data-theme="dark"] .picker-footer { background: var(--rently-subtle-bg) }` every time.
       Everything below is (0,3,0) and wins by specificity in both themes.  DO NOT DROP THE PREFIX. */

    .location-tab-content {
        /* G6: `overflow-y: auto`, `-webkit-overflow-scrolling: touch` and `max-height: 70vh` all
           DELETED. The paper is the single scroll container now (see .search-dropdown-paper) — this
           element having the SAME 70vh cap as its own scrolling parent meant the inner scrollbar was
           the only one that could ever move. */
        background-color: var(--rently-card-bg);
    }

    /* ══ S12-05c — the location view's first-frame SKELETON ═════════════════════════════════════════
       Painted instead of the RentlyAddressPicker for the ~280ms the bar spends morphing from three
       chips into one fused pill. See SearchNav.razor.cs (_locationContentReady) for why: the picker's
       mount was landing inside the morph's own 260ms window, and every property that morph animates is
       a main-thread layout/paint property, so one long task there yields ZERO intermediate frames.

       The geometry deliberately MIRRORS the real view rather than being a generic block — same
       --search-panel-half column split, same gutters, the map's own 240px floor, the right column's
       border-left. The paper tweens its own height (see the interpolate-size rule further down), so a
       skeleton of roughly the right footprint makes the swap at ~280ms a few pixels of growth instead
       of a second, larger animation firing the instant the first one ends.

       NO .search-dropdown-paper prefix here, unlike every rule below it, and that is not an oversight:
       the prefix exists because RentlyAddressPicker's own global sheet declares the identical
       .picker-* and .address-* class names. These four names are unique to this component, so there is
       nothing to out-specify. The MudSkeleton sizes ride inline Height / Width parameters (the idiom
       the sibling search skeleton already uses), which beats MudBlazor's own `.mud-skeleton { height:
       1.2em }` without an !important arms race. Motion: MudSkeleton's wave is already suppressed for
       reduced-motion by the consolidated block at the end of this file, so nothing new is owed there. */
    .location-skeleton {
        display: flex;
        align-items: stretch;
    }

    .location-skeleton-map {
        flex: 0 0 var(--search-panel-half);
        width: var(--search-panel-half);
        padding: var(--search-panel-gutter);
    }

    .location-skeleton-book {
        flex: 1 1 auto;
        min-width: 0;
        padding: var(--search-panel-gutter);
        border-left: 1px solid var(--rently-border);
    }

    .location-skeleton-row {
        display: flex;
        align-items: center;
        gap: var(--rently-space-4, 12px);
        padding: var(--rently-space-3, 10px) 0;
    }

    .location-skeleton-lines {
        flex: 1 1 auto;
        min-width: 0;
    }

    .search-dropdown-paper .location-tab-content .address-picker-container {
        height: auto;   /* the picker's own sheet sets 100%, which has no meaning inside a scroller */
    }

    /* ── Scroll architecture: neutralise every inner scroller and clipper ───────────────────────────
       .picker-content-with-map's `overflow: hidden` is the important one. GoogleLocationTextBox renders
       its autocomplete list as a NON-portalled `position: absolute; z-index: 10000` element, and no
       z-index can escape an overflow ancestor — so the suggestions were being clipped by a box the
       user could not scroll. That single `hidden` was the bug; the z-index is a red herring. */
    .search-dropdown-paper .location-tab-content .picker-content-with-map,
    .search-dropdown-paper .location-tab-content .picker-content,
    .search-dropdown-paper .location-tab-content .address-list {
        overflow: visible;
        max-height: none;
        min-height: 0;
    }

    /* ── Left column: the map ──────────────────────────────────────────────────────────────────────
       2026-07-23 (map-fill pass): the sticky + `align-self: flex-start` pair is GONE. It made the
       column size to its content, which is exactly why the map sat as a 240px strip over a column of
       dead card-bg — the user asked for the map to fill its side. The column now stretches with the
       row (the default) and lays out as a flex column, so the map container can take the leftover
       height below the selected-address header. Sticky was doing nothing real here anyway: the paper
       is the scrollport and it scrolls ~100px at most, and a stretched item's stuck and static
       positions coincide. */
    .search-dropdown-paper .location-tab-content .map-section {
        display: flex;
        flex-direction: column;
        /* Location panel internal geometry:
           The location panel is a balanced two-column map/address workspace. It intentionally keeps
           this internal 50/50 split after the trigger bar moved to three equal fields; the two
           geometries serve different content structures. `width` must accompany `flex-basis` here
           because a stale fixed width would win on this non-growing flex item. */
        flex: 0 0 var(--search-panel-half);
        width: var(--search-panel-half);
        padding: var(--search-panel-gutter);
        /* G6: the divider is re-hung on .picker-content's LEFT edge instead. Once this column became
           sticky + align-self:flex-start it sizes to its own content, so its border stopped partway
           down the panel and the two columns read as a floating box beside a list, not a split layout.
           The right column stretches, so the rule runs the full height there.
           `border-right: 0` is REQUIRED, not implied — the picker's own inline sheet declares
           `.map-section { border-right: 1px solid #e0e0e0 }`, so merely dropping our override left the
           short border in place and we ended up with TWO dividers of different heights. QA-caught. */
        border-right: 0;
        background-color: var(--rently-card-bg);
    }

    /* Fill the column: grow into whatever the address side is tall, floored at the old 240px strip
       and capped so a long address book cannot produce an absurd tower of map. Leftover past the cap
       stays card-bg. The picker's own sheet already forces `#map { height:100% !important }` and
       `.map-container > div { height:100% !important }`, so the Leaflet canvas tracks this box; the
       v7 interop's ResizeObserver re-validates the tile canvas whenever the box changes. */
    .search-dropdown-paper .location-tab-content .map-container,
    .search-dropdown-paper .location-tab-content .map-placeholder {
        flex: 1 1 auto;
        min-height: 240px;
        max-height: 480px;
        border-radius: var(--rently-radius-md, 8px);
    }

    .search-dropdown-paper .location-tab-content .map-container {
        border: 1px solid var(--rently-border);
    }

    .search-dropdown-paper .location-tab-content .map-placeholder {
        background-color: var(--rently-muted-bg);
    }

    .search-dropdown-paper .location-tab-content .map-placeholder .mud-icon-root,
    .search-dropdown-paper .location-tab-content .map-placeholder .mud-typography {
        color: var(--rently-text-tertiary) !important;
    }

    /* Both in-panel headings speak the shared nav-popover voice: small, tracked, uppercase, muted. */
    .search-dropdown-paper .location-tab-content .address-picker-section-title,
    .search-dropdown-paper .location-tab-content .selected-address-header .mud-typography {
        display: flex;
        align-items: center;
        gap: 8px;
        font-size: var(--rently-popover-heading-size) !important;
        font-weight: 700 !important;
        letter-spacing: 0.06em !important;
        text-transform: uppercase !important;
        color: var(--rently-text-secondary) !important;
        margin-bottom: 8px !important;
    }

    /* 2026-07-23: the .selected-address-header arm is gone — that heading no longer carries an icon
       (the CheckCircle was removed in the picker; only the two navigable section titles keep theirs). */
    .search-dropdown-paper .location-tab-content .address-picker-section-title .mud-icon-root {
        color: var(--rently-text-secondary) !important;
        font-size: 1rem !important;
    }

    .search-dropdown-paper .location-tab-content .selected-address-text {
        color: var(--rently-text-body);
        background-color: var(--rently-muted-bg);
        border-radius: var(--rently-radius-sm, 6px);
        padding: var(--rently-space-3, 10px);
    }

    /* ── Right column ──────────────────────────────────────────────────────────────────────────────*/
    .search-dropdown-paper .location-tab-content .picker-content {
        /* G7: the shared alignment rail, so this column's content starts on the same vertical as the
           search view's sections and as the active tab's own content. */
        padding: var(--search-panel-gutter);
        /* The column divider (see .map-section). This column stretches, so the rule runs full height. */
        border-left: 1px solid var(--rently-border);
    }

    .search-dropdown-paper .location-tab-content .mud-divider {
        border-color: var(--rently-border-subtle);
    }

    /* The Google autocomplete field, onto the nav's field vocabulary.
       ⚠ COMPOUND selector (.rz-textbox.custom-google-textbox), NOT descendant. QA-caught: Radzen
       splats the consumer's Class onto the INPUT ELEMENT ITSELF —
       `<input class="rz-textbox rz-state-empty rz-input-md custom-google-textbox">` — there is no
       wrapper carrying it. RentlyAddressPicker's own sheet has the identical latent bug
       (`.custom-google-textbox .rz-textbox { border: 1px solid #e0e0e0; border-radius: 4px }`), which
       is why this field has been rendering with bare Radzen defaults everywhere, not just here.
       Both forms are listed so the rule survives if that wrapper is ever introduced. */
    .search-dropdown-paper .location-tab-content .rz-textbox.custom-google-textbox,
    .search-dropdown-paper .location-tab-content .custom-google-textbox .rz-textbox {
        width: 100%;
        height: 40px;
        padding: 0 38px 0 12px;   /* right pad clears the "use my location" button */
        border: 1px solid var(--rently-border);
        border-radius: var(--rently-radius-sm, 6px);
        background-color: var(--rently-card-bg);
        color: var(--rently-text-body);
        font-size: 0.875rem;
        transition: border-color var(--rently-transition-fast, 0.15s ease),
                    box-shadow var(--rently-transition-fast, 0.15s ease);
    }

    .search-dropdown-paper .location-tab-content .rz-textbox.custom-google-textbox:focus,
    .search-dropdown-paper .location-tab-content .custom-google-textbox .rz-textbox:focus {
        outline: none;
        border-color: var(--section-accent, var(--rently-primary));
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--section-accent, var(--rently-primary)) 18%, transparent);
    }

    .search-dropdown-paper .location-tab-content .rz-textbox.custom-google-textbox::placeholder {
        color: var(--rently-text-tertiary);
    }

    /* "Use my current location" — it sits inside the field, so give it a real hit area and the
       accent ink the rest of the nav uses for icon affordances. */
    .search-dropdown-paper .location-tab-content .glb-location-btn {
        color: var(--section-accent-text, var(--rently-primary-dark));
        border-radius: var(--rently-radius-sm, 6px);
        transition: background-color var(--rently-transition-fast, 0.15s ease);
    }

    .search-dropdown-paper .location-tab-content .glb-location-btn:hover {
        background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 10%, transparent);
    }

    .search-dropdown-paper .location-tab-content .glb-suggestions-container {
        border-radius: var(--rently-popover-radius);
        border: 1px solid var(--rently-border);
        box-shadow: var(--rently-popover-shadow);
        background-color: var(--rently-card-bg);
    }

    /* Address book. The LIST owns the radius and the edge now; the rows are flush inside it, which is
       the same shape .user-menu-dropdown-content uses. `overflow: hidden` here is for clipping the
       first/last row's hover against that radius — it is NOT a scroller (max-height is gone above). */
    .search-dropdown-paper .location-tab-content .address-list {
        border: 1px solid var(--rently-border);
        border-radius: var(--rently-popover-radius);
        padding: 0;
        overflow: hidden;
        background-color: var(--rently-card-bg);
    }

    .search-dropdown-paper .location-tab-content .address-item {
        border-radius: 0;
        border: 0;
        border-bottom: 1px solid var(--rently-border-subtle);
        transition: background-color var(--rently-transition-fast, 0.15s ease);
    }

    .search-dropdown-paper .location-tab-content .address-item:last-child {
        border-bottom: 0;
    }

    .search-dropdown-paper .location-tab-content .address-item:hover {
        background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 8%, transparent);
    }

    /* An inset bar rather than a border: the rows are flush now, so a 1px outline on one of them would
       break the list's own edge. The bar also survives the :hover wash without a specificity fight. */
    .search-dropdown-paper .location-tab-content .address-item.selected {
        background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 12%, transparent);
        box-shadow: inset 3px 0 0 0 var(--section-accent, var(--rently-primary));
    }

    .search-dropdown-paper .location-tab-content .address-item-content {
        padding: 10px 12px;
    }

    /* Tone pass 2026-07-23: the explainer is a label + RentlyFieldHelp "?" row now — flex keeps the
       help button inline with the caption. Font size moves to the label span so the icon button's
       own sizing is untouched. */
    .search-dropdown-paper .location-tab-content .default-address-explainer {
        display: flex;
        align-items: center;
        gap: 2px;
        color: var(--rently-text-tertiary);
        margin-top: var(--rently-space-4, 12px);
    }

    .search-dropdown-paper .location-tab-content .default-address-explainer .default-address-explainer-label {
        font-size: 0.72rem;
    }

    /* ── Ink normalisation, location tab ───────────────────────────────────────────────────────────
       QA-caught by SCREENSHOT, not by the computed-style sweep: the sweep was scoped to
       .search-dropdown-content and this subtree is .location-tab-content, so it reported clean while
       every saved address's sub-line rendered in BRAND RED. Same root cause as the search view —
       RentlyAddressPicker passes Color.Secondary where it means "muted", and in this theme Secondary
       IS the brand red. Five address captions plus three icons.

       Fixed here rather than in the picker's Razor because that markup is shared with the dialog and
       mobile-drawer mounts, which are out of scope for this pass. */
    .search-dropdown-paper .location-tab-content .address-item .mud-typography-caption,
    .search-dropdown-paper .location-tab-content .address-info .mud-typography-caption {
        color: var(--rently-text-tertiary) !important;
    }

    .search-dropdown-paper .location-tab-content .address-item .mud-typography-body2,
    .search-dropdown-paper .location-tab-content .address-name {
        color: var(--rently-text-body) !important;
    }

    /* Anything the picker painted Secondary inside this panel. Scoped to the nav embedding only, so
       the picker's other consumers keep their existing (light-mode) appearance untouched. */
    .search-dropdown-paper .location-tab-content .mud-secondary-text {
        color: var(--rently-text-tertiary) !important;
    }

    /* The selected-row tick stays a real success signal — it is the only non-colour-redundant cue
       distinguishing the chosen address, so it must NOT be flattened to muted ink with the rest. */
    .search-dropdown-paper .location-tab-content .address-item.selected .mud-success-text {
        color: var(--rently-ok-text-strong) !important;
    }

    /* ── Footer ────────────────────────────────────────────────────────────────────────────────────
       Sticky against the PAPER's scrollport — the intermediate `overflow: visible` ancestors above do
       not break that. (0,3,0): this is the rule the picker's dark sheet was beating on source order. */
    .search-dropdown-paper .location-tab-content .picker-footer {
        position: sticky;
        bottom: 0;
        z-index: 2;
        display: flex;
        align-items: center;
        justify-content: flex-end;
        gap: 8px;
        /* G7: --search-panel-gutter, matching .search-panel-footer exactly. The two footers are now
           the same object in both tabs — same height, same insets, same rule, same shadow — so the
           action bar does not shift when you switch views. It also finally STICKS: it is a descendant
           of .location-tab-content, whose enter animation used to carry a transform and therefore
           made it the containing block for the first ~440ms of every open. See the keyframes. */
        padding: var(--rently-space-4, 12px) var(--search-panel-gutter);
        background-color: var(--rently-card-bg);
        border-top: 1px solid var(--rently-border);
        box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.08);
    }

    /* The Confirm button carries the identical AA-clean ink as the search view's action — see
       .search-panel-footer-action for the full derivation. Color.Primary was rendering white on brand
       #35a0ae = 3.09:1, a pre-existing SC 1.4.3 failure on a normal-text label. Literals, because the
       C4 engine reprojects --rently-primary-dark under [data-theme=dark]. */
    .search-dropdown-paper .location-tab-content .picker-footer .mud-button-filled-primary:not(:disabled) {
        background-color: #256f7a !important;
        color: #ffffff !important;
    }

    .search-dropdown-paper .location-tab-content .picker-footer .mud-button-filled-primary:not(:disabled):hover {
        background-color: #1b5a63 !important;
    }

    [data-theme="dark"] .search-dropdown-paper .location-tab-content .picker-footer .mud-button-filled-primary:not(:disabled) {
        background-color: #1b5a63 !important;
    }

    [data-theme="dark"] .search-dropdown-paper .location-tab-content .picker-footer .mud-button-filled-primary:not(:disabled):hover {
        background-color: #14464d !important;
    }

    /* The picker's global `@keyframes pulse` on the confirm button has no reduced-motion guard and
       runs forever. A static accent ring says "this is the primary action" without the throb. */
    .search-dropdown-paper .location-tab-content .confirm-button-active {
        animation: none;
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--section-accent, var(--rently-primary)) 22%, transparent);
    }

    /* The picker renders its own trigger chip even inline, where the location tab in the bar above IS
       the trigger. Hide the duplicate. (0,3,0), was (0,2,0). */
    .search-dropdown-paper .location-tab-content .address-picker-input {
        display: none;
    }

    /* Search Dropdown — G4: shared popover shadow + a matching edge. Top corners stay square because
       this panel meets the fused search bar above it; only the free bottom corners are rounded, and the
       side borders continue the bar's own edge down into the panel so the two read as one object.
       (The bar is split into three chips at rest, but it is always FUSED whenever this panel is open,
       so the panel's full width still matches the component directly above it.) */
    .search-dropdown-paper {
        /* ══ G6 (2026-07-23) — the panel is 4px WIDER than its popover box, pulled 2px left ══════════
           This is not a fudge; it corrects a coordinate-space mismatch that made the "one continuous
           outline" provably discontinuous.

           The bar's ring is an OUTSET box-shadow: it paints 2px OUTSIDE .search-bar-stack's border box.
           This panel's ring is a `border`: it paints INSIDE its own border box. MudBlazor's
           RelativeWidth clamps the popover's max-width to getBoundingClientRect().width of the
           MudPopover's DOM PARENT (.search-container) — a border-box measure that EXCLUDES box-shadow.
           Both boxes are therefore exactly W, and the bar's visible outline came out 4px wider than
           the panel's: a 2px step per side, right at the weld, which is the one place the eye checks.

           Widening by 4px and shifting -2px puts the panel's border in the same coordinate space as
           the bar's ring. Safe because neither .search-popover nor .mud-popover-provider sets
           `overflow`, so the two 2px overhangs render rather than being clipped. */
        width: calc(100% + 4px);
        max-width: none;                 /* was 100% — it would clamp the calc above to the popover box */
        margin-inline-start: -2px;

        /* G6: THE single scroll container for BOTH tabs. There were FIVE nested scrollers here
           (paper -> .search-dropdown-content / .location-tab-content -> .picker-content ->
           .address-list) plus a sixth clipper, .picker-content-with-map's `overflow: hidden`, which is
           what actually ate the Google autocomplete dropdown. Every inner one is neutralised below;
           this is the only element in the panel allowed to scroll. */
        height: auto;                    /* required by the height transition further down */
        max-height: 70vh;
        overflow-y: auto;
        overflow-x: hidden;              /* kept: an over-wide child must never scroll the panel sideways */
        overscroll-behavior: contain;    /* bottoming out the panel must not scroll the page behind it */

        /* ══ G7 (2026-07-23) — reserve the scrollbar gutter ALWAYS ═══════════════════════════════════
           QA-measured: this scrollbar is 10px, and `overflow-y: auto` only takes those 10px off the
           content box WHEN the panel actually scrolls. So the panel's usable width changed by 10px
           depending on state — a long result list scrolls, a short address book does not — and every
           tab switch between the two shifted the entire panel's content sideways by 10px. That is
           precisely the "positioning of elements needs to feel natural when you click between the
           two" complaint, and it is invisible to a settled computed-style check because both states
           are internally consistent.

           `stable` reserves the gutter unconditionally, so the content box is one width in every
           state and nothing moves on a switch. */
        scrollbar-gutter: stable;

        border-radius: 0 0 var(--search-border-radius) var(--search-border-radius);
        /* G5: 2px --search-ring, matching the fused bar's ring exactly, so bar + panel form ONE
           continuous outline with no line at the seam. Was a 1px neutral --rently-border, which met
           the bar's accent ring in a visible colour change right at the weld.
           --search-ring resolves here because it lives on :root — unlike --section-accent, which this
           panel cannot see at all (it is portalled to the document root, outside the section shell). */
        border: 2px solid var(--search-ring);
        border-top: 0;
        box-shadow: var(--rently-popover-shadow);
        /* G6: this was NEVER set, so the panel inherited .mud-paper's
           `background-color: var(--mud-palette-surface)` — the one surface in the whole nav still
           painted from the MudBlazor palette instead of a --rently-* token. */
        background-color: var(--rently-card-bg);
    }

    /* G6: the height tween that makes the tab swap read as a drawer resizing rather than a jump.
       Progressive enhancement — Chrome/Edge 129+ only; Firefox and Safari skip the whole block and
       get today's instant resize, so there is no regression to guard against.
       LONGHANDS, not the `transition:` shorthand: .mud-paper carries `transition: box-shadow 300ms`
       and a shorthand here would silently clobber it.
       Safe against re-anchoring because OverflowBehavior.FlipNever + AnchorOrigin.BottomCenter pin the
       popover's `top` to the bar's bottom — growth is downward-only — and max-height: 70vh clamps the
       `auto` endpoint. */
    /* S7-06 verdict — KEEP. This is a height tween, so it relayouts every frame, and the baseline
       capture did show the panel growing 397.5px -> 558.1px at ~30ms into the 260ms bar morph with a
       19.7ms frame. But the cause was WHEN the growth happened, not the tween: the async results were
       being published mid-morph. The quiet window (SearchNav.razor.cs, AwaitMorphQuietWindowAsync)
       now defers that publish past 280ms, so this tween runs after the morph rather than across it.
       Re-measure before reconsidering — if a post-fix capture still shows long frames inside the
       0-260ms window attributable to this rule, snap it instead. */
    @supports (interpolate-size: allow-keywords) {
        .search-dropdown-paper {
            interpolate-size: allow-keywords;
            transition-property: height;
            transition-duration: var(--search-dur-out);
            transition-timing-function: var(--search-ease-out);
        }
    }

    .search-dropdown-content {
        /* G6: `overflow-y: auto` and `max-height: calc(70vh - 16px)` DELETED — the paper is the one
           scroller now. Two nested scrollers 16px apart meant the outer one could never actually
           scroll, so the panel had a scrollbar that did nothing next to one that did.
           G7: the flat 16px becomes --search-panel-gutter (17px), which is DERIVED from the bar's own
           geometry rather than chosen. See the token. It is what makes the panel's content start on
           the same vertical as the active tab's icon instead of one pixel off it — and one pixel off
           is exactly the kind of near-miss that reads as "nothing lines up" without being nameable. */
        padding: var(--search-panel-gutter);
    }

    /* ══ G6 (2026-07-23) — the panel VIEW transition, and the 220ms blank it replaces ════════════════
       G5 animated each .search-section individually with `fadeInUp` held back 220ms to track the
       MudPopover Delay. That was right for a COLD open and wrong for everything else: on a tab switch
       the popover is already open, so the delay bought nothing except 220ms of empty panel every time
       the user moved between views. The old Location view had no entrance at all, so the two original
       directions did not even behave the same way.

       Now the WRAPPER animates, once, and the delay is a custom property the component sets —
       PanelEnterDelayMs on a cold open, 0 on a tab switch (see SearchNav.razor.cs). One coherent
       unfurl instead of three racing staggers, which is also most of the fix for "the sections aren't
       nicely split up".

       ══ G7 (2026-07-23) — THE TRANSLATE IS GONE. Both keyframes are opacity-only. ═════════════════
       This is not a taste edit. `animation-fill-mode: backwards` applies the from-keyframe for the
       DELAY as well as the run, so on a cold open these wrappers carried a live `transform` for
       220ms + 220ms = ~440ms. A transformed element becomes the containing block for every
       `position: sticky` descendant — and .picker-footer (the location view's action bar, which comes
       up from inside RentlyAddressPicker) is a descendant of .location-tab-content. It has therefore
       never actually stuck for the first 440ms of every open; it only looks correct because the panel
       opens at scrollTop 0, where a sticky element's stuck and static positions coincide.

       The G6 note below spotted the RESIDUAL-transform hazard (which is why it chose `backwards` over
       `both`) but not the during-animation one. The search view's new footer sidesteps it by being a
       direct child of the paper, outside this wrapper — but the picker's footer is inside shared
       markup and cannot be re-parented, so the transform is what had to go.

       What is lost: the two views used to enter from their own side (Search left, Location right),
       which read as a directional swap. What replaces it: the panel's own height tween and the tab
       indicator's slide, both of which still carry the direction. A 10px x-offset was never doing
       much work next to those.

       `backwards`, not `both` — keep it. It applies the from-keyframe during the delay and then
       reverts to the natural style, which is still the right choice for an opacity-only enter. */
    @keyframes searchPanelEnterFromLeft {
        from {
            opacity: 0;
        }
    }

    @keyframes searchPanelEnterFromRight {
        from {
            opacity: 0;
        }
    }

    .search-dropdown-content {
        animation: searchPanelEnterFromLeft 220ms var(--search-ease-out) backwards;
        /* MUST follow the shorthand — `animation` resets animation-delay to 0s. */
        animation-delay: var(--panel-enter-delay, 0ms);
    }

    .location-tab-content {
        animation: searchPanelEnterFromRight 220ms var(--search-ease-out) backwards;
        animation-delay: var(--panel-enter-delay, 0ms);
    }

    /* Sections are grouped by a hairline BETWEEN them, not by a rule UNDER each header.
       The old markup drew a <MudDivider> immediately below every section heading while leaving the
       sections themselves separated by nothing but a 24px margin — so each heading read as if it
       belonged to the group ABOVE it, and the panel had four rules doing the opposite of grouping.
       The headings are already uppercase, tracked and muted; they need no underline.
       NOTE: .search-section is desktop-only. Do NOT touch .search-animate-in further down — the mobile
       drawer still uses it. */
    .search-section {
        margin-bottom: 0;
    }

    .search-section + .search-section {
        margin-top: var(--rently-space-6, 16px);
        padding-top: var(--rently-space-6, 16px);
        border-top: 1px solid var(--rently-border-subtle);
    }

    /* ══ G7 (2026-07-23) — the SHORTCUTS band ════════════════════════════════════════════════════════
       "Popular searches and recent searches also just blend in with everything."

       They did, and the reason is that the panel had THREE equal siblings separated by TWO equally
       weak hairlines, each inset inside the panel's padding so it stopped short of both edges. Two
       weak breaks between three peers is not a hierarchy — it is a list of three things, and the eye
       reads a short rule as a continuation mark rather than a divider.

       So there is now ONE break, and it means something: above it is what we found, below it is what
       to try instead. It is expressed three ways at once, which is what makes it read at a glance:
         - a full-bleed surface change (--rently-subtle-bg, the same wash the dashboards use for a
           secondary band)
         - a full-bleed 1px rule at the top edge — not the subtle token, the real --rently-border
         - and the panel's own gutter restored inside, so the content column never moves

       Full-bleed is the load-bearing part. `margin-inline: calc(-1 * gutter)` pulls the band out to
       the paper's inner edge and `padding-inline: gutter` puts the text back where it was, so the
       rule spans the whole panel while the copy stays on the alignment rail. A rule that stops 17px
       short of each edge is the thing that was reading as a continuation mark.

       The hairline BETWEEN Popular and Recent survives untouched: .search-section + .search-section
       above still applies inside this band, and being the weaker of the two rules is now correct —
       it separates two peers inside one group. */
    .search-shortcuts {
        margin-top: var(--rently-space-6, 16px);
        margin-inline: calc(-1 * var(--search-panel-gutter));
        margin-bottom: calc(-1 * var(--search-panel-gutter));   /* the band runs to the paper's floor */
        padding: var(--rently-space-6, 16px) var(--search-panel-gutter);
        background-color: var(--rently-subtle-bg);
        border-top: 1px solid var(--rently-border);
    }

    /* When there are no results the band is the panel's ONLY content, so it must not pretend to be a
       secondary layer under something that is not there. :first-child covers exactly that case. */
    .search-dropdown-content > .search-shortcuts:first-child {
        margin-top: calc(-1 * var(--search-panel-gutter));
        background-color: transparent;
        border-top: 0;
    }

    /* ══ G6 (2026-07-23) — the CONSOLIDATED reduced-motion block used to sit HERE, and that was still
       too high. It claimed to be "at the END of the section", but ~750 lines of animated rules follow
       it — .search-result-item (transition: all), .search-chip (transition: all + a translateY hover)
       and .search-history-item (transition: all) all won the source-order tie and were NEVER
       suppressed, exactly the same class of escape the G5 note described for the divider and button.
       The block now lives at the true end of the file. Do not re-seed one here. */

    .search-section-header {
        display: flex;
        align-items: center;
        gap: 8px;
        margin-bottom: 8px;   /* G6: was 12px — it was clearing a divider that no longer exists */
    }

    /* G4 — section headings across the nav popovers speak with one voice: a small, tracked, uppercase
       label in muted ink, not a 1rem subtitle. The three headings also carried three DIFFERENT brand
       colours on their icons (Color.Primary teal / Color.Secondary red / Color.Info blue), which read
       as a rainbow inside a single panel; they all resolve to the same muted ink now.
       !important + (0,3,0): MudBlazor's role classes (.mud-primary-text et al) and its
       .font-weight-medium text utility are themselves !important, so nothing weaker would land. */
    .search-dropdown-content .search-section-header .mud-typography {
        font-size: var(--rently-popover-heading-size) !important;
        font-weight: 700 !important;
        letter-spacing: 0.06em !important;
        text-transform: uppercase !important;
        color: var(--rently-text-secondary) !important;
    }

    .search-dropdown-content .search-section-header .mud-icon-root {
        color: var(--rently-text-secondary) !important;
        font-size: 1rem !important;
    }

    /* ══ G7 (2026-07-23) — ONE LIST SHELL, used by every list in the nav popovers ════════════════════
       "There is no separation between the rentables that show for me."

       The results were a flex column of free-floating rows with an 8px gap and a transparent border
       that only appeared on hover. Recent searches were the same. Meanwhile the address book in the
       OTHER TAB was already a proper bordered list with flush rows and hairline dividers. Three lists
       in one component, two vocabularies, and the better one was the one the user was not complaining
       about.

       So this is the address book's shell (see .search-dropdown-paper .location-tab-content
       .address-list), lifted verbatim onto the other two: the LIST owns the border and the radius,
       the rows are flush inside it, and a hairline separates them. `overflow: hidden` is here to clip
       the first and last row's hover wash against that radius — it is NOT a scroller (the paper is
       the panel's only scroller).

       Now results, recent searches and the address book are the same object, and switching tabs no
       longer switches design languages. */
    .search-results-list,
    .search-history-list {
        display: flex;
        flex-direction: column;
        gap: 0;
        border: 1px solid var(--rently-border);
        border-radius: var(--rently-popover-radius);
        overflow: hidden;
        background-color: var(--rently-card-bg);
    }

    /* ══ The result ROW — a 3x2 grid, not a flex line ════════════════════════════════════════════════
       "Their details are just floating around, I can't clearly identify everything and it doesn't
        feel like my eyes have a natural focus point."

       Diagnosis: the row had five children laid out in a single flex line — avatar, an info column
       stacking name/price/pills, a meta column stacking rating/location, and a chevron — so nothing
       in row N shared a vertical with anything in row N+1. Two of the five were themselves stacks, so
       the row was really three levels deep. Colour and spacing cannot fix a row that has no columns.

       The grid is:
              48px          1fr              auto
            +-------+-------------------+-----------+
       row1 | thumb | name              | price     |
       row2 | thumb | rating - dist-loc | tags      |
            +-------+-------------------+-----------+
       Two rows, three columns, fixed. Names align down the list, prices align down the list, and the
       eye gets one entry point per row (the name) and one accent (the price) instead of five peers.

       `border: 0; border-radius: 0` — the LIST owns the edge now. The row keeps only the hairline
       that separates it from the next one. */
    .search-result-item {
        display: grid;
        grid-template-columns: 48px minmax(0, 1fr) auto;
        grid-template-rows: auto auto;
        grid-template-areas:
            "thumb name price"
            "thumb meta tags";
        align-items: center;
        column-gap: 12px;
        row-gap: 2px;
        padding: 10px 12px;   /* matches .address-item-content, so rows are the same height in both tabs */
        cursor: pointer;
        /* G6: was `transition: all var(--search-transition)`. `all` re-animated colour AND geometry on
           every unrelated repaint — and it is also why this rule escaped reduced-motion suppression,
           since that block used to sit ABOVE it in source order. Narrowed to what actually changes. */
        transition: background-color var(--rently-transition-fast, 0.15s ease);
        border: 0;
        border-bottom: 1px solid var(--rently-border-subtle);
        border-radius: 0;
        /* G6: the row is an <a href> now (it was a div with @onclick — keyboard-unreachable). Strip
           the link chrome; the row's own hover is the affordance. */
        color: inherit;
        text-decoration: none;
    }

    .search-results-list .search-result-item:last-child {
        border-bottom: 0;
    }

        .search-result-item:hover {
            background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 8%, transparent);
            /* G6: `transform: translateX(4px)` DELETED. No other list in the nav — account menu,
               address book, history — moves under the cursor, and inside a scrolling panel the nudge
               fought the scrollbar at the right edge. The wash IS the hover.
               G7: the hover border-color went with it. Flush rows share edges, so tinting one row's
               border also tints its neighbour's — and against the list's own edge it read as a
               rendering fault. */
        }

    /* ══ G7 — the VIRTUAL-FOCUS indicator, which did not exist before ════════════════════════════════
       MoveActiveOption has always set aria-selected="true" on the arrowed-to row and pointed the
       input's aria-activedescendant at it — but NOTHING in wwwroot/css matched [aria-selected]. So a
       keyboard user pressed ArrowDown, saw no change whatsoever, pressed Enter, and was navigated to
       a rental they had never seen highlighted. That is a plain SC 2.4.7 failure, and it gets worse
       in G7, which promotes ArrowDown to one of the primary ways to open the panel at all.

       With aria-activedescendant the AUTHOR owns the indicator: DOM focus never moves, so the UA
       draws nothing. The inset bar is the same one .address-item.selected uses in the other tab —
       one vocabulary — and the outline is what carries the 3:1 (#256f7a on #ffffff = 5.78:1).
       SearchNav.razor.cs scrolls the row into view; an indicator below the 70vh fold is the same
       failure wearing a different hat. */
    .search-result-item[aria-selected="true"] {
        background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 14%, transparent);
        box-shadow: inset 3px 0 0 0 var(--section-accent-text, var(--rently-primary-dark));
        outline: 2px solid var(--section-accent-text, var(--rently-primary-dark));
        outline-offset: -2px;
    }

    /* Literals — the C4 engine live-reprojects --rently-primary-dark to #35a0ae on dark (3.97:1 on
       this wash, a fresh fail). #74d0dc is 8.22:1 on #1e293b. Same trap as .pill-collection. */
    [data-theme="dark"] .search-result-item[aria-selected="true"] {
        box-shadow: inset 3px 0 0 0 #74d0dc;
        outline-color: #74d0dc;
    }

    .search-result-name {
        grid-area: name;
        min-width: 0;
    }

    .search-result-name .mud-typography {
        font-weight: 600;
        color: var(--rently-text-primary);
    }

    .mud-avatar.search-result-thumb {
        grid-area: thumb;
        /* (0,2,0) is REQUIRED. MudBlazor's own `.mud-avatar.mud-avatar-medium { width: 40px }` is
           (0,2,0), so a bare `.search-result-thumb` would lose. 48px is not reachable through the
           Size enum at all — 9.7 offers 24 / 40 / 56 — and 48 is the number the LOADING SKELETON
           above already uses, so Size.Medium's 40px was shifting every row 8px the moment results
           replaced the skeleton. This is a CLS fix as much as a sizing one. */
        width: 48px;
        height: 48px;
        flex-shrink: 0;
        align-self: center;
    }

    /* The price: top-right, on the name's own baseline. It was a caption stacked UNDER the name, which
       buried the one number a renter actually scans for behind the title and above a pill row. */
    .search-result-price {
        grid-area: price;
        text-align: end;
        white-space: nowrap;
    }

    .search-result-pricing {
        color: var(--section-accent-text, var(--rently-primary-dark));
        font-weight: 600;
        font-size: 0.875rem;
        line-height: 1.3;
    }

    /* One muted line, not a right-aligned stack competing with the price. */
    .search-result-meta {
        grid-area: meta;
        display: flex;
        align-items: center;
        flex-wrap: nowrap;
        gap: 8px;
        min-width: 0;
        overflow: hidden;
    }

    /* AverageRatingStar is a SHARED component (Client/Components) rendering the compact
       `★ 4,5 (12)` grammar on a `.rently-rating` root, sized for listing cards and detail pages.
       At this panel's caption scale that widget is taller and louder than the row's own name
       line — scale and mute it HERE ONLY; do not touch the component.
       !important guards against sheet order: rently-rating.css is linked ahead of this file, and
       both sets of selectors are single-class, so equal specificity would hand the win to whichever
       loads last.
       flex-shrink: 0 so the rating keeps its size and the LOCATION is what truncates — a clipped
       "(4,8" would be worse than a clipped suburb name. Rows with reviews wrap the rating in a
       MudTooltip, and 9.7 renders a real `.mud-tooltip-root` element between the meta row and the
       rating's root — there the WRAPPER is the meta row's flex item, so it carries the guarantee;
       the bare `> .rently-rating` branch keeps an unwrapped rating shrink-proof too. */
    .search-result-meta > .rently-rating,
    .search-result-meta > .mud-tooltip-root {
        flex-shrink: 0;
    }

    .search-result-meta > .rently-rating,
    .search-result-meta > .mud-tooltip-root > .rently-rating {
        gap: 2px;
    }

    .search-result-meta .rently-rating__avg,
    .search-result-meta .rently-rating__count {
        font-size: 0.75rem !important;
        line-height: 1.4;
        color: var(--rently-text-tertiary) !important;
    }

    .search-result-meta .mud-typography {
        font-size: 0.75rem !important;
        line-height: 1.4;
        padding: 0 !important;
        color: var(--rently-text-tertiary) !important;
    }

    .search-result-meta .mud-icon-root {
        font-size: 0.95rem !important;
        width: 0.95rem !important;
        height: 0.95rem !important;
    }

    /* The star keeps its amber — it is the one place in this row where colour carries meaning rather
       than decoration, and muting it with the rest of the meta line would flatten a real signal. */
    .search-result-meta > .rently-rating .mud-icon-root,
    .search-result-meta > .mud-tooltip-root > .rently-rating .mud-icon-root {
        color: #f59e0b !important;   /* --rently-warning; literal, the C4 engine reprojects the token */
    }

    .search-result-pills {
        grid-area: tags;
        display: flex;
        flex-wrap: nowrap;
        justify-content: flex-end;
        gap: 4px;
    }

    .search-pill {
        display: inline-flex;
        align-items: center;
        padding: 1px 8px;
        border-radius: 12px;
        font-size: 0.65rem;
        font-weight: 500;
        line-height: 1.4;
        white-space: nowrap;
    }

    /* C4: pill TEXT colours (#2a8a96 / #c5361f / #2e7d32) + the green cancellation wash encode
       category semantics → fold into the C4 semantic palette (no exact tokens today). */
    .pill-collection {
        background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 12%, transparent);
        color: #2a8a96;
    }

    .pill-delivery {
        background-color: rgba(var(--rently-secondary-rgb), 0.10);
        color: #c5361f;
    }

    .pill-cancellation {
        background-color: rgba(76, 175, 80, 0.12);
        color: #2e7d32;
    }

    /* Dark: lift the parked C4 category-pill inks (the :10 + :1402-1403 "stay raw, tagged for
       C4's semantic-palette engine" note; Initiative C shipped complete without closing them) to
       dark-AA hue-mates. Light byte-identical (these rules are inert without [data-theme=dark]).
       Small text (0.65rem/500) on the dark search surface — desktop MudPopover paper (which
       TELEPORTS to the popover provider near <body>) + mobile .mobile-search-drawer-content, both
       #1e293b — needs 4.5:1 (SC 1.4.3). Keep this GLOBAL and keyed on <html data-theme>: the
       desktop dropdown teleports out of SearchNav, so an inline-ancestor / .razor.css scope would
       silently miss it. Pre-fix the raw light inks were near-invisible on slate (collection 3.02 /
       delivery 2.53 / cancellation 2.37 : 1 — all SC 1.4.3 FAIL). Post-fix (accessibility-expert,
       each ink over its own color-mix wash on #1e293b): collection 6.9 / delivery 7.13 /
       cancellation 8.65 : 1. collection is a LITERAL #74d0dc, NOT var(--rently-primary-dark): the
       C4 palette engine reprojects --rently-primary-dark live to the mid-tone brand #35a0ae
       (3.97:1 — a fresh FAIL on this wash), so the token is unusable here; #74d0dc is the intended
       light teal and matches this block's hardcoded-hex style. delivery/cancellation use
       -text-strong tokens, which the engine does NOT reproject, so they render the AA pastels. */
    [data-theme="dark"] .pill-collection   { color: #74d0dc; }                            /* light teal 6.9:1 — LITERAL; var(--rently-primary-dark) reprojects live to #35a0ae (3.97:1 FAIL) */
    [data-theme="dark"] .pill-delivery     { color: var(--rently-critical-text-strong); }  /* #fca5a5 red-300, 7.13:1 (token NOT reprojected) */
    [data-theme="dark"] .pill-cancellation { color: var(--rently-ok-text-strong); }         /* #86efac green-300, 8.65:1 (token NOT reprojected) */
    /* D30 — pricing caption (the D29 pill twin, one line above them in SearchNav): same teleport +
       reprojection mechanism, but NO color-mix wash → ink lands on bare #1e293b. Reprojected
       --rently-primary-dark (#35a0ae) = 4.73:1 resting (marginal) / 4.22:1 on the :hover 8%-teal
       wash (SC 1.4.3 FAIL). Literal #74d0dc (token reprojects; no non-reprojected teal -text-strong
       exists) = 8.22:1 resting / 7.33:1 hover. Light byte-identical: light --rently-primary-dark is
       AA-by-construction (AaTextOnPage darkens to ~5.5:1 on white; static #256f7a = 5.78:1). */
    [data-theme="dark"] .search-result-pricing { color: #74d0dc; }   /* light teal 8.22:1 on #1e293b — LITERAL; var(--rently-primary-dark) reprojects live to #35a0ae */

    .search-result-location {
        display: flex;
        align-items: center;
        gap: 4px;
        white-space: nowrap;
    }

    .text-truncate {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Search Chips */
    .search-chips-container {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
    }

    .search-chip {
        cursor: pointer;
        /* G6: was `transition: all` — another rule the old reduced-motion block sat above and missed. */
        transition: background-color var(--rently-transition-fast, 0.15s ease),
                    border-color var(--rently-transition-fast, 0.15s ease);
        /* ══ G7 (2026-07-23) — two fixes in three declarations ═══════════════════════════════════════
           1. `margin: 0`. MudBlazor 9.7 ships `.mud-chip { margin: 4px }`. .search-chips-container
              declares `gap: 8px` on top of it, so the chips have actually been sitting SIXTEEN pixels
              apart, and the first chip has been inset 4px from the left — i.e. off the alignment rail
              its own section heading sits on. The class lands on .mud-chip itself (MudBlazor appends
              the consumer Class there), so this is a (0,1,0) vs (0,1,0) tie broken by source order,
              and this sheet loads after MudBlazor.min.css. No !important needed — unlike the
              Bootstrap `.gap-N` trap documented on .search-bar-stack, MudBlazor's margin here carries
              no !important.
           2. The LABEL INK. Color="Color.Primary" renders the text in brand #35a0ae, which is 2.94:1
              on the shortcuts band's --rently-subtle-bg — a straight SC 1.4.3 failure at 0.75rem. The
              chip keeps its accent BORDER (a UI component needs only 3:1, and it clears that); the
              label drops to body ink, which is what a chip label should have been anyway.
              !important because MudBlazor's own .mud-chip-outlined.mud-chip-color-primary sets colour
              through a role class. */
        margin: 0;
        color: var(--rently-text-body) !important;
        border-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 45%, transparent) !important;
    }

        .search-chip:hover {
            /* G6: the `translateY(-2px)` lift and its drop shadow are DELETED. Chips that rise off the
               surface are a different vocabulary from every other list in this panel, and three
               vocabularies in one dropdown is most of why it read as messy. Same accent wash as the
               result rows, just a touch stronger so an outlined chip still reads as hovered. */
            background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 10%, transparent);
            border-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 40%, transparent);
        }

    /* Search History
       G7: the `.search-history-list` rule that sat here (flex column, gap 8px) is DELETED — the list
       now shares the bordered flush shell declared with .search-results-list above, and because that
       rule is EARLIER in the file a surviving copy here would have silently won on source order and
       re-opened the gap. */
    .search-history-item {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 6px 12px;   /* the row already sits in a bordered list; it needs less air than a card did */
        /* G6: was `transition: all` — the third rule the old reduced-motion block sat above. */
        transition: background-color var(--rently-transition-fast, 0.15s ease);
        /* G7: flush inside the list, like every other row in the nav popovers. Was a free-floating
           8px-radius card with a transparent border that only materialised on hover. */
        border: 0;
        border-bottom: 1px solid var(--rently-border-subtle);
        border-radius: 0;
        background-color: transparent;
    }

    .search-history-list .search-history-item:last-child {
        border-bottom: 0;
    }

    /* G6: this is a real <button> now (it was a div with @onclick — keyboard-unreachable). Strip the
       UA button chrome so it keeps rendering as a row. */
    .search-history-clickable {
        display: flex;
        align-items: center;
        flex: 1;
        cursor: pointer;
        min-width: 0;
        appearance: none;
        background: none;
        border: 0;
        padding: 0;
        margin: 0;
        font: inherit;
        color: inherit;
        text-align: start;
    }

    /* Same wash as .search-result-item and .address-item — one hover vocabulary across all three
       lists. The hover border-color is gone with the rest of the card chrome: flush rows share an
       edge, so tinting one row's border tints its neighbour's too. */
    .search-history-item:hover {
        background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 8%, transparent);
    }

    .search-history-text {
        flex: 1;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Empty State */
    .empty-search-state {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 48px 16px;
        gap: 16px;
        text-align: center;
    }

    /* ══ G7 (2026-07-23) — the search view's ACTION FOOTER ═══════════════════════════════════════════
       "I feel that when I open the rental search popup it's not very clear to me what to do next."

       It was not, because there was nothing to do next: the only forward action was a full-width text
       button buried at the end of the results section, above two more sections, so it scrolled away.
       The address tab meanwhile had a proper sticky Confirm bar. Two panels of the same component,
       one with a persistent answer to "and then?" and one without.

       Every value below is copied from .picker-footer (the address tab's bar) on purpose — same
       padding, same border, same shadow, same sticky rule, so the action bar does not move when you
       switch tabs. That stillness is most of what makes the two views read as one component.

       It is a DIRECT CHILD OF THE PAPER, not of .search-dropdown-content. The paper is the panel's
       only scrollport, which is what sticky needs; and the content wrapper carries an enter animation
       whose from-keyframe would otherwise make it a containing block (see the note on the keyframes).
       Being outside also means it escapes the content's gutter padding and can run full-bleed with
       its own rule, which is the shape a footer wants. */
    .search-panel-footer {
        position: sticky;
        bottom: 0;
        z-index: 2;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--rently-space-4, 12px);
        padding: var(--rently-space-4, 12px) var(--search-panel-gutter);
        background-color: var(--rently-card-bg);
        border-top: 1px solid var(--rently-border);
        box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.08);
    }

    /* The hint earns its place by saying something the button does not: that the KEYBOARD route
       exists — and since the tone pass it echoes the actual query ("…for "laptops" in Cape Town").
       Muted, so it never competes. Now a flex row (plain div, no longer MudText): the TEXT span
       carries min-width:0 + ellipsis, so when space runs out it is the query text that truncates,
       never the "add a location" action sitting after it. Typography restated here because the
       MudText caption class went with the markup change. */
    .search-panel-footer .search-panel-footer-hint {
        color: var(--rently-text-tertiary);
        font-size: 0.75rem;
        line-height: 1.66;
        display: flex;
        align-items: center;
        gap: 6px;
        min-width: 0;
        white-space: nowrap;
    }

    .search-panel-footer .search-panel-footer-hint .search-hint-text {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* The inline route to the Location view for users with no location context. Link-shaped (the
       underline is what makes it read as an action inside a muted sentence), ink pinned to the same
       literals as .search-panel-footer-action's rationale: #256f7a on card 5.78:1; dark can't use
       --rently-primary-dark (the C4 engine reprojects it back to #35a0ae) so #74d0dc is literal. */
    .search-panel-footer .search-hint-action {
        flex: 0 0 auto;
        background: none;
        border: 0;
        padding: 2px;
        margin: 0;
        font: inherit;
        font-weight: 600;
        color: #256f7a;
        text-decoration: underline;
        text-underline-offset: 2px;
        cursor: pointer;
        border-radius: 4px;
    }

    .search-panel-footer .search-hint-action:hover {
        color: #1b5a63;
    }

    .search-panel-footer .search-hint-action:focus-visible {
        outline: 2px solid var(--section-accent-text, var(--rently-primary-dark));
        outline-offset: 2px;
    }

    [data-theme="dark"] .search-panel-footer .search-hint-action {
        color: #74d0dc;
    }

    [data-theme="dark"] .search-panel-footer .search-hint-action:hover {
        color: #9adee8;
    }

    /* ══ The primary action's ink — and why it is a literal ══════════════════════════════════════════
       Color.Primary paints white on brand #35a0ae = 3.09:1. The MudButton label is 0.875rem/500,
       i.e. NORMAL text, so the bar is 4.5:1 and that is a plain SC 1.4.3 failure. (3.09:1 is the
       accepted SYS-07 brand figure, which licenses the colour as a brand surface — not as a ground
       for small text.)

       #256f7a -> white 5.78:1. Dark uses a literal too because the C4 palette engine live-reprojects
       --rently-primary-dark back to #35a0ae under [data-theme=dark]; #1b5a63 -> white 7.81:1.

       Deliberately NOT --rently-secondary. The bar's own Search button is brand red, and reusing it
       here would put two competing filled reds 300px apart AND import the known light-mode
       white-on-#EF412c 3.84:1 fail (GlobalCssDarkAuditSweep.md section 7) into a brand-new surface.
       Teal also reads correctly as "the panel's action" against the bar's "the page's action".
       :not(:disabled) so Mud's grey disabled state survives the transient searching flash. */
    .search-panel-footer .search-panel-footer-action:not(:disabled) {
        background-color: #256f7a !important;
        color: #ffffff !important;
    }

    .search-panel-footer .search-panel-footer-action:not(:disabled):hover {
        background-color: #1b5a63 !important;   /* white 7.81:1 */
    }

    [data-theme="dark"] .search-panel-footer .search-panel-footer-action:not(:disabled) {
        background-color: #1b5a63 !important;
    }

    [data-theme="dark"] .search-panel-footer .search-panel-footer-action:not(:disabled):hover {
        background-color: #14464d !important;
    }

    /* ══ G6 (2026-07-23) — INK NORMALISATION inside the dropdown ══════════════════════════════════════
       MudBlazor's Color.Secondary resolves to the BRAND RED here, and the markup used it as if it meant
       "muted". The result: a red chevron on every result row, a red pin + caption under every address,
       a red clock on every history row, and a 3rem red SearchOff dominating the empty state. Only the
       section-header icons had ever been neutralised. The Razor now passes Color.Inherit at those call
       sites; these rules define what "inherit" resolves to, in one place, for both themes. */
    .search-dropdown-content .empty-search-state .mud-icon-root,
    .search-dropdown-content .empty-search-state .mud-typography {
        color: var(--rently-text-tertiary) !important;
    }

    /* G7: `.search-result-item > .mud-icon-root` is DELETED, not re-scoped. It existed to mute the
       trailing ChevronRight on every result row, and that chevron is gone — the row is an <a href>
       whose hover wash already says it navigates, and removing five identical glyphs is what freed
       the right-hand column for the price. A rule matching nothing is worse than no rule: it reads as
       coverage during the next audit. */

    .search-dropdown-content .search-result-location .mud-icon-root {
        color: var(--rently-text-tertiary) !important;
        font-size: 0.95rem !important;
    }

    .search-dropdown-content .search-result-location .mud-typography {
        color: var(--rently-text-tertiary) !important;
    }

    .search-dropdown-content .search-history-item .search-history-clickable .mud-icon-root {
        color: var(--rently-text-tertiary) !important;
    }

    /* A red X sitting on every history row shouted louder than the row it belonged to. Reveal it on
       row hover — and on :focus-visible, or it would become unreachable for keyboard users, which is
       the classic way a "quieter" hover affordance turns into an accessibility regression. */
    .search-dropdown-content .search-history-item .mud-icon-button {
        opacity: 0;
        transition: opacity var(--rently-transition-fast, 0.15s ease);
    }

    .search-dropdown-content .search-history-item:hover .mud-icon-button,
    .search-dropdown-content .search-history-item .mud-icon-button:focus-visible {
        opacity: 1;
    }

    /* G6: the location chip is a real <button> now (it was a div with @onclick, so it was unreachable
       by keyboard entirely). Strip the UA chrome so it still renders as a field. */
    .location-picker-section,
    .date-picker-section {
        appearance: none;
        font: inherit;
        color: inherit;
        text-align: start;
        cursor: pointer;
    }

    .date-picker-section {
        justify-content: flex-start;
        width: 100%;
    }

    .date-picker-icon {
        flex: 0 0 auto;
        color: var(--section-accent-text, var(--rently-primary-dark));
    }

    .date-picker-label {
        display: block;
        flex: 1 1 auto;
        min-width: 0;
        text-align: left;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .date-tab-content {
        padding: 22px var(--search-panel-gutter);
        background-color: var(--rently-card-bg);
        animation: searchViewEnter 0.2s ease-out both;
    }

    .date-tab-heading,
    .date-tab-footer {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 16px;
    }

    .date-tab-heading {
        margin-bottom: 12px;
    }

    .search-nav-appbar .date-clear-button.mud-button-root,
    .mobile-search-drawer .date-clear-button.mud-button-root {
        color: #a72e1f;
    }

    [data-theme="dark"] .search-nav-appbar .date-clear-button.mud-button-root,
    [data-theme="dark"] .mobile-search-drawer .date-clear-button.mud-button-root {
        color: var(--rently-secondary-light, #ff8a7a);
    }

    .search-date-range-calendar {
        width: 100%;
        margin: 14px auto 16px;
        overflow-x: auto;
        border: 1px solid var(--rently-border);
        border-radius: var(--rently-radius-md, 8px);
        background: var(--rently-card-bg);
        scrollbar-width: thin;
    }

    .search-date-range-calendar__grid {
        min-width: 0;
        border-radius: var(--rently-radius-md, 8px);
    }

    .date-tab-heading .mud-button-root,
    .date-tab-footer .mud-button-root {
        min-height: 44px;
    }

    .date-tab-footer {
        padding-top: 14px;
        border-top: 1px solid var(--rently-border);
    }

    .date-selection-summary {
        color: var(--rently-text-secondary);
        font-weight: 500;
    }

    .date-selection-summary--mobile {
        margin-top: 18px;
    }

    .date-selection-summary--error {
        color: var(--mud-palette-error, #b3261e);
    }

    .date-helper-text {
        color: var(--rently-text-secondary);
    }

    .date-picker-skeleton {
        display: grid;
        gap: 16px;
    }

    /* Nav-local sr-only. There is no global utility for this in the repo — the clip recipe is inlined
       per component (see StoreTemplatePicker.razor.css). Clip, never display:none: the text has to stay
       in the accessible name. */
    .search-nav-sr-only {
        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;
    }

    /* Tablet Styles */
    .tablet-search-bar {
        /* Initiative C · C2 Pt3.C — Tinted Glass search surface; no bottom border (Blend-gradient seam). */
        background: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 16%, rgba(255, 255, 255, 0.70));
        -webkit-backdrop-filter: blur(12px);
        backdrop-filter: blur(12px);
        padding: 12px 20px !important;
    }

    .tablet-search-container {
        width: 100%;
    }

    .tablet-search-field {
        background-color: var(--rently-card-bg); /* C5 Pt3c.C: token-swap (light #fff, flips slate on dark) */
        padding: 4px 8px;
        border-radius: var(--search-border-radius);
        display: flex;
        align-items: center;
        gap: 12px;
        cursor: pointer;
        box-shadow: var(--search-shadow);
        transition: all var(--search-transition);
        width: 100%;
        border: 1px solid var(--rently-border);
        color: inherit;
        font: inherit;
        text-align: start;
    }

        .tablet-search-field:hover {
            box-shadow: var(--search-shadow-hover);
            transform: translateY(-1px);
        }

        .tablet-search-field:active {
            transform: scale(0.98);
        }

    .tablet-search-content {
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: space-around;
        gap: 12px;
    }

    .search-summary-segment {
        appearance: none;
        flex: 1 1 0;
        min-width: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 8px;
        padding: 4px;
        border: 0;
        border-radius: var(--rently-radius-sm, 6px);
        background: transparent;
        color: inherit;
        font: inherit;
        text-align: center;
        cursor: pointer;
        min-height: 44px;
    }

    .search-summary-segment--query {
        justify-content: flex-start;
    }

    .search-summary-segment:hover {
        background: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 8%, transparent);
    }

    .search-summary-segment:focus-visible,
    .mobile-location-picker:focus-visible,
    .mobile-date-picker:focus-visible {
        outline: 2px solid var(--section-accent-text, var(--rently-primary-dark));
        outline-offset: 2px;
    }

    .tablet-search-label {
        flex: 1;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        color: #424242;
    }

    /* Mobile Styles */
    .mobile-search-bar {
        /* Initiative C · C2 Pt3.C — Tinted Glass search surface (mobile); Blend-gradient seam (no border). */
        background: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 16%, rgba(255, 255, 255, 0.70));
        -webkit-backdrop-filter: blur(12px);
        backdrop-filter: blur(12px);
        padding: 8px 16px !important;
    }

    .mobile-search-container {
        width: 100%;
    }

    .mobile-search-field {
        background-color: var(--rently-card-bg); /* C5 Pt3c.C: token-swap (light #fff, flips slate on dark) */
        padding: 4px 8px;
        border-radius: var(--search-border-radius);
        display: flex;
        align-items: center;
        gap: 8px;
        cursor: pointer;
        box-shadow: var(--search-shadow);
        transition: all var(--search-transition);
        margin: 0 !important;
        width: 100%;
        border: 1px solid var(--rently-border);
        color: inherit;
        font: inherit;
        text-align: start;
    }

        .mobile-search-field:active {
            transform: scale(0.98);
        }

    .mobile-search-content {
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: space-around;
    }

    .mobile-search-label {
        color: #757575;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        flex: 1 1 0;
        min-width: 0;
        max-width: none;
        text-align: center;
    }

    /* Mobile Search Drawer */
    .mobile-search-drawer {
        border-top-left-radius: 16px;
        border-top-right-radius: 16px;
        overflow: hidden;
        display: flex;
        flex-direction: column;
    }

    .drawer-handle-container {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        height: 24px;
        display: flex;
        align-items: center;
        justify-content: center;
        background-color: #f5f5f5;
        border-top-left-radius: 16px;
        border-top-right-radius: 16px;
        z-index: 1;
        cursor: grab;
    }

        .drawer-handle-container:active {
            cursor: grabbing;
        }

    .drawer-handle {
        width: 40px;
        height: 4px;
        background-color: #bdbdbd;
        border-radius: 2px;
        transition: width 0.2s ease;
    }

    .drawer-handle-container:hover .drawer-handle {
        width: 60px;
        background-color: #9e9e9e;
    }

    .mobile-search-drawer-header {
        background-color: #f5f5f5;
        border-bottom: 1px solid #e0e0e0;
        padding: 16px;
        padding-top: 28px;
        flex-shrink: 0;
    }

    .mobile-search-drawer-header .mud-icon-button {
        width: 44px;
        height: 44px;
    }

    .mobile-search-drawer-content {
        flex: 1;
        overflow-y: auto;
        background-color: var(--rently-card-bg); /* C5 Pt3c.C: token-swap (light #fff, flips slate on dark) */
        display: flex;
        flex-direction: column;
        -webkit-overflow-scrolling: touch;
    }

    .mobile-search-drawer-footer {
        padding: 16px;
        background-color: var(--rently-card-bg); /* C5 Pt3c.C: token-swap (light #fff, flips slate on dark) */
        box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
        flex-shrink: 0;
    }

    .mobile-search-drawer-footer .mud-button-root {
        min-height: 44px;
    }

    /* Mobile Search Input */
    .search-input-wrapper,
    .location-input-wrapper,
    .date-input-wrapper {
        width: 100%;
    }

    .search-input-mobile {
        width: 100%;
    }

    /* Mobile Location Picker */
    .mobile-location-picker {
        appearance: none;
        width: 100%;
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 12px 16px;
        cursor: pointer;
        transition: background-color var(--search-transition),
                    border-color var(--search-transition),
                    transform var(--search-transition);
        border-radius: var(--search-border-radius);
        border: 1px solid var(--rently-border);
        background: var(--rently-card-bg);
        color: inherit;
        font: inherit;
        text-align: start;
    }

    .mobile-date-picker {
        appearance: none;
        width: 100%;
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 12px 16px;
        cursor: pointer;
        font: inherit;
        color: inherit;
        text-align: start;
        background: var(--rently-card-bg);
        border: 1px solid var(--rently-border);
        border-radius: var(--search-border-radius);
        transition: background-color var(--search-transition),
                    border-color var(--search-transition),
                    transform var(--search-transition);
    }

    .mobile-date-picker:hover {
        background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 5%, transparent);
        border-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 30%, transparent);
    }

    .mobile-date-picker:active {
        transform: scale(0.98);
    }

    .mobile-date-display {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .mobile-date-page {
        min-height: 100%;
        padding: 16px;
        background: var(--rently-card-bg);
    }

    .mobile-date-intro {
        margin-bottom: 12px;
    }

    .search-date-range-calendar--mobile {
        margin-block: 16px 0;
        overflow-x: hidden;
    }

    .search-date-range-calendar--mobile .mud-picker-content {
        min-height: 300px;
        padding-inline: 0;
    }

        .mobile-location-picker:hover {
            background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 5%, transparent);
            border-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 30%, transparent);
        }

        .mobile-location-picker:active {
            background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 10%, transparent);
            transform: scale(0.98);
        }

    .mobile-location-display {
        flex: 1;
    }

    /* Mobile Search Results */
    .mobile-search-results-container {
        flex: 1;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }

    .mobile-search-section {
        margin-bottom: 24px;
        animation: fadeInUp 0.3s ease-out forwards;
    }

    .mobile-search-result {
        padding: 12px 0;
        border-bottom: 1px solid #f5f5f5;
        cursor: pointer;
        transition: background-color 0.2s ease;
    }

        .mobile-search-result:hover {
            background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 5%, transparent);
        }

        .mobile-search-result:active {
            background-color: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 10%, transparent);
        }

        .mobile-search-result:last-child {
            border-bottom: none;
        }

    .mobile-history-item {
        padding: 8px 0;
    }

    .mobile-history-clickable {
        display: flex;
        align-items: center;
        flex: 1;
        cursor: pointer;
        min-width: 0;
        min-height: 44px;
        padding: 0;
        border: 0;
        background: transparent;
        color: inherit;
        font: inherit;
        text-align: left;
    }

    .mobile-history-item .mud-icon-button {
        width: 44px;
        height: 44px;
    }

    /* Mobile Empty State */
    .empty-search-state-mobile {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 48px 16px;
        text-align: center;
        color: #757575;
    }

    /* Mobile Location Page */
    .mobile-location-page {
        flex: 1;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        background-color: var(--rently-card-bg); /* C5 Pt3c.C: token-swap (light #fff, flips slate on dark) */
    }

    /* Search Action Button */
    .search-action-button {
        text-transform: none;
        font-weight: 500;
        letter-spacing: 0.5px;
        transition: all var(--search-transition);
    }

    /* Confirm Location Button */
    .confirm-location-button {
        animation: search-nav-pulse 2s infinite;
        text-transform: none;
        font-weight: 500;
    }

    /* Search Chip Mobile */
    .search-chip-mobile {
        max-width: calc(50% - 4px);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* Animations */
    @keyframes fadeInUp {
        from {
            opacity: 0;
            transform: translateY(10px);
        }

        to {
            opacity: 1;
            transform: translateY(0);
        }
    }

    @keyframes search-nav-pulse {
        0% {
            box-shadow: 0 0 0 0 color-mix(in srgb, var(--section-accent, var(--rently-primary)) 40%, transparent);
        }

        70% {
            box-shadow: 0 0 0 10px transparent;
        }

        100% {
            box-shadow: 0 0 0 0 transparent;
        }
    }

    .search-animate-in {
        animation: fadeInUp 0.3s ease-out;
    }

    /* G5 (2026-07-22) — the second "Override address picker styles" block that used to live here has
       been DELETED. It was a duplicate of the .search-nav-appbar-scoped block above, written with
       !important and a different `padding: 6px 0`, so it silently defeated that block's documented
       (0,3,0)-beats-the-picker's-inline-sheet strategy and made the location chip's inner padding
       disagree with the search chip's. The surviving block is the scoped one; the picker is
       display:flex + align-items:center + height:100%, so its text stays vertically centred without
       the padding.
       Its :hover wash is gone deliberately, not by oversight: the CHIP owns the hover affordance in
       both states (box-shadow + border-color when split, the .tab-inactive wash when fused). Washing
       only the inner picker painted a second, smaller hover rectangle inside the first — which is
       exactly why the scoped block above already sets :hover to transparent. */

    /* Responsive adjustments */
    @media (max-width: 1479px) {
        .search-bar-wrapper {
            width: 100%;
        }
    }

    @media (max-width: 959px) {
        .search-bar-stack {
            height: 44px;
        }

        .search-button {
            min-width: 90px;
        }
    }

    @media (max-width: 599px) {
        .mobile-search-bar {
            padding: 6px 12px !important;
        }

        .mobile-search-field {
            padding: 4px 8px;
        }

        .mobile-search-label {
            font-size: 0.875rem;
        }

        .mobile-search-drawer-header {
            padding: 12px;
            padding-top: 24px;
        }

        .mobile-search-drawer-footer {
            padding: 12px;
        }
    }

    /* Touch-friendly targets */
    @media (hover: none) and (pointer: coarse) {
        .search-result-item,
        .mobile-search-result,
        .search-history-item,
        .mobile-history-item {
            min-height: 48px;
        }

        .search-chip,
        .search-chip-mobile {
            min-height: 44px; /* (C2 Pt3.B) WCAG 2.5.5 — 44px touch target */
            padding-block: 6px;
        }
    }

    /* Safe area support */
    @supports (padding: max(0px)) {
        .mobile-search-drawer-content {
            padding-left: max(0px, env(safe-area-inset-left));
            padding-right: max(0px, env(safe-area-inset-right));
        }

        .mobile-search-drawer-footer {
            padding-bottom: max(16px, env(safe-area-inset-bottom));
        }
    }

    /* Fix popover width */
    .mud-popover-provider .mud-popover.mud-popover-relative-width {
        width: 100% !important;
    }

    /* Accessibility */
    .search-result-item:focus-visible,
    .search-chip:focus-visible,
    .search-history-item:focus-visible,
    .mobile-location-picker:focus-visible {
        outline: 2px solid var(--section-accent-text, var(--rently-primary-dark));
        outline-offset: 2px;
    }

    /* ════════════════════════════════════════════════════════════════════════════════════════════════
       Initiative C · C5 Pt3c.C — DARK chrome (SearchNav). White field/drawer surfaces flip via the
       var(--rently-card-bg) token-swap above; these DARK-ONLY rules re-colour the off-palette grays (no
       token equal) so the LIGHT literals stay byte-identical. Attribute-driven (tracks the C5 Pt3b toggle),
       replacing the old prefers-color-scheme stub. */
    /* Tinted-Glass search bars on dark (same rationale as the MainNav appbar above): swap the 70%-alpha WHITE
       scrim to dark slate so the frosted search bar goes dark. Keyed off data-search-nav-surface (the search
       split, Pt3.C-ii) and :not(hairline):not(solid) so it ONLY applies to the Tinted-Glass search surface —
       the hairline variant already darkens via var(--rently-card-bg), and the solid variant brings its own
       dark accent fill (below); equal-base specificity would otherwise let this win over them by source order. */
    html[data-theme="dark"][data-search-nav-surface="tintedglass"] .search-nav-appbar,
    html[data-theme="dark"][data-search-nav-surface="tintedglass"] .tablet-search-bar,
    html[data-theme="dark"][data-search-nav-surface="tintedglass"] .mobile-search-bar {
        background: color-mix(in srgb, var(--section-accent, var(--rently-primary)) 16%, rgba(15, 23, 42, 0.72));
    }

    [data-theme="dark"] .search-bar-stack.search-open {
        background-color: var(--rently-muted-bg);
    }

    /* G6 (2026-07-23): the dark override that used to sit here is DELETED, not relocated. It existed
       only because the light rule was a hardcoded 45% WHITE film that flashed light on a dark bar.
       That rule is now the standard accent color-mix wash, which composites correctly in both themes,
       so a dark-only variant would be a second answer to a question that no longer has two. */

    /* a11y (C5 Pt3c.C gate): text-secondary, NOT text-tertiary — the placeholder must clear 4.5:1 (SC 1.4.3)
       on the WORST-CASE open-field surface (.search-open flips the field to --rently-muted-bg #334155, where
       #94a3b8 = 3.82:1 FAILS). #cbd5e1 = 6.62:1 on #334155 (and 8–9:1 on the resting card/subtle surfaces). */
    [data-theme="dark"] .search-input input::placeholder,
    [data-theme="dark"] .search-location-input input::placeholder {
        color: var(--rently-text-secondary) !important;
    }

    /* G6 (2026-07-23): the dark `.location-tab-content .picker-footer` override is DELETED. It was
       (0,2,0), as was the light rule it was meant to complement — and the picker's OWN
       `[data-theme="dark"] .picker-footer` is also (0,2,0) and later in document order, so in practice
       the picker won and the footer painted --rently-subtle-bg regardless of what either of these
       said. The footer is now (0,3,0) under .search-dropdown-paper and needs no dark variant: it reads
       --rently-card-bg, which the token layer flips on its own. */

    [data-theme="dark"] .tablet-search-label,
    [data-theme="dark"] .mobile-search-label {
        color: var(--rently-text-secondary);
    }

    [data-theme="dark"] .empty-search-state-mobile {
        color: var(--rently-text-tertiary);
    }

    [data-theme="dark"] .drawer-handle-container {
        background-color: var(--rently-subtle-bg);
    }

    [data-theme="dark"] .drawer-handle {
        background-color: var(--rently-border-strong);
    }

    [data-theme="dark"] .drawer-handle-container:hover .drawer-handle {
        background-color: var(--rently-text-muted);
    }

    [data-theme="dark"] .mobile-search-drawer-header {
        background-color: var(--rently-subtle-bg);
        border-bottom-color: var(--rently-border);
    }

    [data-theme="dark"] .mobile-location-picker {
        border-color: var(--rently-border);
    }

    [data-theme="dark"] .mobile-search-result {
        border-bottom-color: var(--rently-border-subtle);
    }

    .address-loading-container {
        display: flex;
        align-items: center;
        padding: 0 16px;
        min-width: 200px;
    }

/* ══ Map marker pulse (map-fill pass, 2026-07-23) ═══════════════════════════════════════════════════
   The subtle "you are here" cue on the selected-address pin. Drawn by leafletMapsInterop.js v8 as a
   SECOND, non-interactive 0x0 divIcon marker at the same latlng — see the note there for why the
   animation must live on this INNER span and never on the marker root (Leaflet owns translate3d on
   roots). GLOBAL to every LocationMap consumer (nav panel, mobile drawer, meetup dialogs) —
   deliberate: one pin vocabulary everywhere. Decorative only (aria-free, non-interactive), and the
   teal reads on OSM tiles in both themes (tiles stay light in dark mode), so no dark literal needed. */
.rently-marker-pulse {
    pointer-events: none;
}

.rently-marker-pulse__ring {
    position: absolute;
    left: 0;
    top: 0;
    width: 36px;
    height: 36px;
    margin: -18px 0 0 -18px;   /* centre the ring on the 0x0 icon's anchor = the pin's latlng */
    border: 2px solid var(--rently-primary, #35a0ae);
    border-radius: 50%;
    opacity: 0.55;
    animation: rentlyMarkerPulse 2s ease-out infinite;
}

@keyframes rentlyMarkerPulse {
    0%   { transform: scale(0.55); opacity: 0.55; }
    70%  { transform: scale(1.35); opacity: 0; }
    100% { transform: scale(1.35); opacity: 0; }
}

/* ════════════════════════════════════════════════════════════════════════════════════════════════════
   G6 (2026-07-23) — THE consolidated prefers-reduced-motion block. Singular, and LAST IN THE FILE.

   Why it lives here and nowhere else: these overrides and the rules they suppress are all equal
   specificity, so they win ONLY by source order. There used to be TWO blocks (one at ~line 1665, one
   at ~1987) and BOTH claimed to be the consolidated one. Between them they silently missed
   .search-result-item, .search-chip and .search-history-item — three rules carrying `transition: all`
   that kept animating for every reduced-motion user, exactly the failure the G5 comment described for
   .search-divider and .search-button one release earlier. Two blocks made the escape inevitable,
   because there was no single answer to "where does a new selector go?".

   THE RULE: if you add an animated selector anywhere in this file, add it HERE. Never seed a new
   reduced-motion block above it. Nothing may be appended below this block.

   QA note: assert `transition-property: none` / `animation-name: none` PER ELEMENT — never a duration
   of 0s, which Chrome emulates as 1e-05s, and never by trusting the selector list to have applied.
   Reading the live computed value per element is how the original escape was caught.
   ════════════════════════════════════════════════════════════════════════════════════════════════════ */
html[data-theme="dark"] .search-date-field input {
    color-scheme: dark;
}

@media (prefers-reduced-motion: reduce) {

    /* ── The bar morph ─────────────────────────────────────────────────────────────────────────────*/
    .search-bar-stack,
    .search-input-section,
    .location-picker-section,
    .date-picker-section,
    .tablet-search-field,
    .mobile-search-field,
    .search-summary-segment,
    .search-divider,
    .search-button,
    .search-nav-appbar .location-picker-section .address-picker-input,
    /* The tab indicators. NOTE what is suppressed and what is NOT: the transition goes, the
       indicator STAYS. It is the only SC 1.4.11 signal distinguishing the active tab from the
       inactive one, so suppressing the element itself would delete the accessible state cue for
       precisely the users this block exists to protect. It jumps instead of sliding. */
    .search-bar-stack.search-open .search-input-section::after,
    .search-bar-stack.search-open .location-picker-section::after,
    .search-bar-stack.search-open .date-picker-section::after,

    /* ── The panel ────────────────────────────────────────────────────────────────────────────────*/
    .search-dropdown-paper,                 /* the interpolate-size height tween */
    .search-result-item,                    /* was escaping suppression entirely */
    .search-history-item,                   /* was escaping suppression entirely */
    .search-chip,                           /* was escaping suppression entirely */
    /* G7 additions. The aria-selected row is listed for its transition only — the INDICATOR itself
       must survive, for the same reason the tab indicator does: it is the sole SC 2.4.7 cue for a
       virtual-focus combobox, so suppressing it would delete the state signal for exactly the users
       this block protects. It jumps instead of easing. */
    .search-result-item[aria-selected="true"],
    .search-panel-footer .search-panel-footer-action,
    .search-dropdown-content .search-history-item .mud-icon-button,
    .search-dropdown-paper .location-tab-content .address-item,
    .search-dropdown-paper .location-tab-content .rz-textbox.custom-google-textbox,
    .search-dropdown-paper .location-tab-content .glb-location-btn,
    .mobile-date-picker {
        transition: none;
    }

    .search-section,
    .search-dropdown-content,               /* view-enter animation */
    .location-tab-content,                  /* view-enter animation */
    .date-tab-content,
    .search-animate-in,
    .z-index-search-modal .mud-overlay-scrim {
        animation: none;
    }

    /* MudPopover renders Delay/Duration as INLINE transition-delay / transition-duration longhands.
       A stylesheet rule cannot beat an inline declaration without !important. The visibility flip is
       discrete, so it lands on the same frame and the click-target guard still holds. */
    .search-popover,
    .search-popover.mud-popover-open {
        transition-delay: 0ms !important;
        transition-duration: 0ms !important;
    }

    /* GLOBAL and DELIBERATE. RentlyAddressPicker's inline sheet declares
       `.confirm-button-active { animation: pulse 2s infinite }` at (0,1,0), later in document order,
       so !important is the only way to reach it from here. Unscoping this is intentional: an
       unguarded infinite pulse is worth killing for every consumer of the picker, not just the nav,
       and it is inert for anyone without the preference set. */
    .confirm-button-active {
        animation: none !important;
    }

    /* MudBlazor 9.7 ships ZERO prefers-reduced-motion rules of its own — verified against the
       installed MudBlazor.min.css. Skeletons and spinners animate for every reduced-motion user in
       this app unless we stop them. The wave animates a ::after pseudo-element, so targeting
       .mud-skeleton-wave alone does nothing.
       The spinner is SLOWED, not stopped: a frozen indeterminate ring reads as a hung request. */
    .mud-skeleton-pulse,
    .mud-skeleton-wave::after {
        animation: none;
    }

    .mud-progress-circular.mud-progress-indeterminate,
    .mud-progress-circular-indeterminate-child {
        animation-duration: 3s;
    }

    /* The map pin pulse: the ANIMATION goes, the ring STAYS as a static halo — same doctrine as the
       tab indicator above: the ring is the "this is the selected spot" cue, so deleting the element
       would remove the signal for exactly the users this block protects. */
    .rently-marker-pulse__ring {
        animation: none;
        opacity: 0.5;
    }

    /* ── MainNav chrome + the mobile drawers (S7-06) ───────────────────────────────────────────────
       Everything below was previously suppressed by an unscoped `* { animation-duration: 0.01ms
       !important; transition-duration: 0.01ms !important }` block that sat mid-file (around line
       1172). That block is now GONE, and these selectors are why it has to be replaced rather than
       simply deleted: it was the only thing standing between a reduced-motion user and the whole nav.

       Two reasons it had to go. It was `*`, so it also reached into every OTHER stylesheet on the
       page — catalogue-map.css, reconnect-modal.css and notification-templates.css were silently
       depending on it and now carry their own end-of-file guards. And it asserted a 0.01ms DURATION
       rather than `none`, which leaves transition-property intact, still fires transitionend, and
       cannot be asserted by the per-element QA probe this file's doctrine requires. */
    .main-nav-appbar,
    .mobile-nav-appbar,
    .drawer-backdrop,
    .logo-link,
    .logo-loading,
    .user-avatar,
    .mobile-user-avatar,
    .help-link,
    .user-menu,
    .user-card,
    .login-button,
    .logout-button,
    .mobile-logo,
    .mobile-user-card,
    .mobile-login-button,
    .mobile-logout-submit-btn,
    .user-drawer-header,
    .mobile-nav-drawer,
    .list-item-content,
    .list-item-content::before,
    .list-item-icon,
    /* Mobile/tablet search surfaces — these carry `transition: all var(--search-transition)` and sit
       in a max-width block far below the main search rules, so the search list above never saw them. */
    .tablet-search-field,
    .mobile-search-field,
    .mobile-location-picker,
    .mobile-search-result,
    .search-action-button,
    .drawer-handle {
        transition: none;
    }

    /* The staggered row entrances. animation-delay is left alone deliberately: with the animation
       itself off there is nothing to delay, and listing the delays would only add selectors to keep
       in sync. .drawer-subheader carries a delayed fade, so it needs the same treatment. */
    .main-nav-animate-in,
    .slide-in,
    .slide-in-right,
    .slide-in-up,
    .logo-loaded,
    .user-menu-popover,
    .user-menu-nav-shortcut,
    .drawer-subheader,
    .mobile-search-section {
        animation: none;
    }

    /* The three INFINITE loops in this file. These are the ones that matter most — an unguarded
       infinite animation is the exact WCAG 2.2.2 failure this block exists to prevent, and it runs
       forever rather than for 300ms. The elements stay; only the motion stops. */
    .notification-chip,
    .loading-shimmer,
    .confirm-location-button {
        animation: none;
    }

    /* S12-05b — the shared nav count pill. We do not declare a transition on it, but MudBlazor's own
       base rule does: `.mud-badge { transition: .3s cubic-bezier(0.25, 0.8, 0.5, 1) }` with no
       property list, so every count change eases its geometry and colour. Owning the element's look
       (see .rently-nav-count) means owning its motion too — this file's doctrine is that an animated
       selector belongs in THIS block, and MudBlazor 9.7 ships no reduced-motion rules of its own.
       (0,2,0) so it beats the single-class MudBlazor rule regardless of which sheet loaded last —
       the same reasoning as the pill rule itself, and the reason this is not folded into the
       single-class list above. */
    .rently-nav-count .mud-badge {
        transition: none;
    }

    /* !important, and MEASURED rather than assumed. The four drawer slides and the drawer rows are
       styled by MudBlazor's own compound selectors (`.mud-drawer.mud-drawer-pos-left.mud-drawer--open`,
       `.mud-list-item`), which outrank a bare single-class rule from this file, so the plain
       `transition: none` above computed to `transform` on .mobile-nav-drawer and `background-color`
       on .drawer-list-item — caught by the post-change reduced-motion probe, not by reading the CSS.
       The removed `*` nuke had been hiding this behind its own !important.
       Same escalation pattern, and the same justification, as .confirm-button-active and
       .search-popover above: !important is the only way to reach a rule we do not own. */
    .mobile-nav-drawer,
    .mobile-user-drawer,
    .mobile-category-drawer,
    .mobile-search-drawer,
    .drawer-list-item,
    .menu-item,
    .user-menu-item {
        transition: none !important;
    }
}
