/* Glassy chrome — app hosts (web + maui), every world EXCEPT high-contrast, so
   the animated backdrop shows through the sidebar + bottom nav. Each world's
   own --os-glass-* tokens tint the glass to that world. high-contrast opts out
   entirely: opaque chrome, no blur, no translucency. */
html[data-host="web"]:not([data-theme="high-contrast"]) .side-nav--v2,
html[data-host="maui"]:not([data-theme="high-contrast"]) .side-nav--v2 {
    background: var(--os-glass-bg-strong);
    backdrop-filter: blur(var(--os-glass-blur));
    -webkit-backdrop-filter: blur(var(--os-glass-blur));
    border-right: 1px solid var(--os-glass-border);
    box-shadow: var(--os-shadow-md), var(--os-glass-highlight);
}

html[data-host="web"]:not([data-theme="high-contrast"]) .bottom-nav--v2,
html[data-host="maui"]:not([data-theme="high-contrast"]) .bottom-nav--v2 {
    background: var(--os-glass-bg-strong);
    backdrop-filter: blur(var(--os-glass-blur));
    -webkit-backdrop-filter: blur(var(--os-glass-blur));
    border-top: 1px solid var(--os-glass-border);
    box-shadow: var(--os-shadow-md), var(--os-glass-highlight);
}

/* Shell transparency — the fixed backdrop layer (z-index 0) shows through the
   .app-layout shell on every world except high-contrast. This rule MUST live
   here (a plain stylesheet), not in AppLayout.razor.css: Blazor's scoped-CSS
   compiler emits `:global()` literally, the browser drops the rule as invalid,
   and the shell silently stays opaque. */
html[data-host="web"]:not([data-theme="high-contrast"]) .app-layout,
html[data-host="maui"]:not([data-theme="high-contrast"]) .app-layout {
    background-color: transparent;
}

/* high-contrast: no backdrop layer at all — display none beats any JS state.
   Same scoped-CSS constraint as above: html-anchored, so it lives here. */
html[data-theme="high-contrast"] .os-animated-bg {
    display: none;
}

/* ── Optional collapsed sidebar (desktop / tablet) ─────────────────────────
   The sidebar can be collapsed to an icon rail. State carrier is a single
   attribute on the document root — html[data-sidenav="collapsed"]; absent (or
   any other value) means expanded, which is the DEFAULT, so the whole mode is
   opt-in and nothing changes for a user who never touches the toggle.

   Why <html> and not a Blazor field: each host's <head> carries a tiny inline
   boot script that reads localStorage('os.sidenav.collapsed') and stamps the
   attribute BEFORE first paint, so a returning user never sees a 260px sidebar
   snap to 76px. Blazor cannot run that early, and two owners of one attribute
   would fight. sidenav.js owns every later flip.

   These rules MUST live here (a plain stylesheet) and not in
   SideNav.razor.css / AppLayout.razor.css, for the same reason the shell
   transparency above does: Blazor's scoped-CSS compiler emits `:global()`
   literally, the browser drops the rule as invalid, and html-anchored
   selectors silently never apply. Targeting the component's own class names
   from a global sheet is fine — `b-*` scoping restricts a component's OWN
   stylesheet, not other sheets.

   Everything is wrapped in the ≥768px media query the shell's desktop layout
   uses: below it .app-sidebar is `display: none` and BottomNav is the nav, so
   a collapsed rail would have nothing to act on. */
@media (min-width: 768px) {
    /* Animate the rail width on the shell, not the <nav> inside it — the nav is
       width:100% of whatever the shell gives it. */
    .app-sidebar {
        transition: width var(--os-transition-normal),
                    min-width var(--os-transition-normal);
    }

    /* Specificity note: AppLayout.razor.css's scoped `.app-sidebar[b-…]` is
       (0,2,0) and sets width/min-width, so an unanchored `.app-sidebar` here
       would lose. `html[data-sidenav="collapsed"] .app-sidebar` is (0,2,1) and
       wins — which is another reason the state lives on <html>. */
    html[data-sidenav="collapsed"] .app-sidebar {
        width: var(--os-sidebar-width-collapsed);
        min-width: var(--os-sidebar-width-collapsed);
    }

    /* Brand: the wordmark goes, the 42px logo tile stays and centres, so
       branding survives the collapse (Thimo's explicit requirement). The row
       becomes a column so the collapse toggle sits UNDER the logo rather than
       fighting it for 76px of width. */
    html[data-sidenav="collapsed"] .side-nav-brand {
        flex-direction: column;
        gap: var(--os-space-sm);
        padding-left: var(--os-space-xs);
        padding-right: var(--os-space-xs);
    }

    html[data-sidenav="collapsed"] .side-nav-app-name {
        display: none;
    }

    /* Icons only. The label <span> is removed from the layout AND from the
       accessibility tree by `display: none` — which is exactly why every link
       carries an aria-label as well as the `title` tooltip, or a collapsed
       link would be an unnamed link to a screen reader. */
    html[data-sidenav="collapsed"] .side-nav-link > span {
        display: none;
    }

    html[data-sidenav="collapsed"] .side-nav-link {
        justify-content: center;
        gap: 0;
        padding-left: var(--os-space-xs);
        padding-right: var(--os-space-xs);
    }

    html[data-sidenav="collapsed"] .side-nav-links {
        padding-left: var(--os-space-xs);
        padding-right: var(--os-space-xs);
    }

    /* `margin-left: auto` is what parks the toggle at the trailing edge of the
       EXPANDED brand row. In the collapsed column it would shove the button off
       the logo's centre line, so it has to be reset here. */
    html[data-sidenav="collapsed"] .side-nav-collapse-toggle {
        margin-left: 0;
    }

    /* Chevron points the way the click goes: "<" to collapse, ">" to expand. */
    html[data-sidenav="collapsed"] .side-nav-collapse-toggle svg {
        transform: rotate(180deg);
    }
}

/* A width animation is motion. Honour the OS-level opt-out — the mode still
   works, it just arrives instantly. The chevron's own reduced-motion override
   lives in SideNav.razor.css instead: its base rule is scoped
   (`.side-nav-collapse-toggle svg[b-…]`, specificity 0-2-1) so an unscoped
   selector here would lose the cascade and silently keep animating. */
@media (prefers-reduced-motion: reduce) {
    .app-sidebar {
        transition: none;
    }
}
