/* nav.css — ShowHelm app shell styles (sidebar + topbar + bottom-bar).
 *
 * Layers on top of portal.css (41-token design system) and portal-v2.css
 * (additional spacing/type/elevation/motion tokens, when present). NEVER
 * introduces new hex colors — every color comes through a token.
 *
 * 1.61.0.0 — Now loaded universally (portal_assets_tags adds it on every
 * page) so portal_admin_topbar() / portal_worker_topbar() can emit the
 * v2 sidebar+topbar shell without per-page CSS includes. Adds a defensive
 * kill-switch that hides the legacy XP bottom taskbar everywhere — the
 * markup is no longer emitted but the rule protects against stale callers.
 *
 * Layout model
 * ────────────
 * Desktop (>= 1024px):
 *   ┌──────┬─────────────────────────────────────────┐
 *   │      │  TOPBAR (56px tall, sticky)             │
 *   │      ├─────────────────────────────────────────┤
 *   │ SIDE │                                         │
 *   │ BAR  │  MAIN CONTENT                           │
 *   │ 240  │                                         │
 *   │ /64  │                                         │
 *   └──────┴─────────────────────────────────────────┘
 *
 * Mobile (< 1024px): sidebar slides in as a drawer over a backdrop.
 * Mobile (< 768px):  bottom-tab bar appears, content padded to clear it.
 *
 * Local fallback tokens — only consumed if portal-v2.css hasn't defined
 * them already. Doubled-up var() chains let portal-v2.css win.
 */

:root {
    --shell-sidebar-w:           260px;
    --shell-sidebar-w-collapsed: 104px;
    --shell-topbar-h:            52px;
    --shell-stepper-h:           28px;   /* ≈ half the topbar — section stepper */
    --shell-bottombar-h:         64px;

    --shell-row-h:               40px;
    --shell-section-gap:         18px;

    --shell-radius-sm:           6px;
    --shell-radius-md:           8px;
    --shell-radius-lg:           12px;

    --shell-motion-fast:         120ms;
    --shell-motion-base:         200ms;
    --shell-easing:              cubic-bezier(0.4, 0, 0.2, 1);

    --shell-z-sidebar:           40;
    --shell-z-topbar:            50;
    --shell-z-backdrop:          45;
    --shell-z-bottombar:         55;
    --shell-z-drawer:            60;
}

/* ───────── Skip link ───────── */
.shell-skiplink {
    position: absolute;
    top: -100px;
    left: 12px;
    z-index: 999;
    background: var(--brand-secondary);
    color: var(--text-onbrand);
    padding: 8px 14px;
    border-radius: var(--shell-radius-sm);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    transition: top var(--shell-motion-fast) var(--shell-easing);
}
.shell-skiplink:focus {
    top: 12px;
    outline: 2px solid var(--brand-accent);
    outline-offset: 2px;
}

/* ───────── Outer grid ───────── */
/* When the v2 shell is on the page, lock the entire document to the
 * viewport. Without this, body's default `min-height: 100%` (set in
 * portal.css) lets body grow past the viewport whenever any fixed
 * element or post-shell markup nudges it, which on mobile Safari
 * collapses the URL bar and drags the topbar/sidebar with it. With
 * html + body pinned to 100dvh + overflow:hidden, the URL bar stays
 * put, the topbar + sidebar never move, and only #app-content scrolls. */
html:has(.app-shell),
html:has(.app-shell) body {
    height: 100dvh;
    max-height: 100dvh;
    overflow: hidden;
    overscroll-behavior: none;
}
.app-shell {
    display: grid;
    grid-template-columns: var(--shell-sidebar-w) 1fr;
    /* Row 2 ("stepper") is `auto` — it collapses to 0 height on pages
     * that emit no #app-stepper element (e.g. Home), and otherwise sizes
     * to the strip's own --shell-stepper-h. Sidebar spans all three rows. */
    grid-template-rows: var(--shell-topbar-h) auto 1fr;
    grid-template-areas:
        "sidebar topbar"
        "sidebar stepper"
        "sidebar content";
    height: 100dvh;
    overflow: hidden;
    background: var(--bg-body);
    transition: grid-template-columns var(--shell-motion-base) var(--shell-easing);
}
.app-shell[data-sidebar-collapsed="1"] {
    grid-template-columns: var(--shell-sidebar-w-collapsed) 1fr;
}
@media (prefers-reduced-motion: reduce) {
    .app-shell, .app-shell * {
        transition: none !important;
        animation: none !important;
    }
}

/* ───────── Sidebar ─────────
 * The Portal app shell emits `<aside id="app-sidebar">` (bootstrap.php).
 * `.app-sidebar` is the canonical class used by the design-system
 * preview kit (design_ui/ui_kits/portal/kit.css); add it as an alias
 * so any future component that uses the class hits the same styling
 * and any future markup change to a `<aside class="app-sidebar">`
 * pattern doesn't lose the chrome. (Bug #2, sitewide CSS sweep.) */
#app-sidebar,
.app-sidebar {
    grid-area: sidebar;
    background: var(--bg-card);
    border-right: 1px solid var(--border-light);
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    /* Pin to viewport: 100dvh exact height + align-self:start so the grid
     * doesn't stretch us to fill the row when content below grows past
     * the viewport. position:sticky needs a clamped element to actually
     * stick — min-height would defeat it. (1.62.2.0) */
    height: 100dvh;
    max-height: 100dvh;
    align-self: start;
    position: sticky;
    top: 0;
    z-index: var(--shell-z-sidebar);
    overflow: hidden;
}
/* The fixed chat bar (.sr-chat-bar, chat.css) overlays the bottom edge of
 * the viewport across the full width — including the sidebar. Reserve its
 * height inside the sidebar so the footer's user card clears it. Mirrors
 * the body padding-bottom chat.css applies for the same reason. */
body:has(#srChatBar:not(.is-hidden)) #app-sidebar,
body:has(#srChatBar:not(.is-hidden)) .app-sidebar {
    padding-bottom: var(--sr-chat-bar-h, 42px);
}

/* Sidebar brand — kit parity. The wordmark renders in Helvetica Neue /
 * Arial Black 900 italic with negative tracking (the only italic in the
 * system). Mark is 28px square. */
.sidebar__brand {
    display: flex;
    align-items: center;
    gap: 10px;
    height: var(--shell-topbar-h);
    padding: 0 16px;
    border-bottom: 1px solid var(--border-light);
    color: var(--text-strong);
    text-decoration: none;
    flex-shrink: 0;
}
.sidebar__brand img,
.sidebar__brand svg,
.sidebar__brand .showhelm-mark { width: 22px; height: 22px; flex-shrink: 0; }
.sidebar__brand-text {
    font-family: 'Helvetica Neue', 'Arial Black', Arial, sans-serif;
    font-weight: 900;
    font-style: italic;
    font-size: 19px;
    letter-spacing: -0.5px;
    color: var(--text-strong);
    white-space: nowrap;
}
.app-shell[data-sidebar-collapsed="1"] .sidebar__brand { padding: 0; justify-content: center; }
.app-shell[data-sidebar-collapsed="1"] .sidebar__brand-text { display: none; }

.sidebar__scroll {
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 8px 10px 12px;
    /* Scrollbar hidden visually — scrolling still works via
     * mouse-wheel, trackpad swipe, keyboard, and touch. (1.62.2.1) */
    scrollbar-width: none;       /* Firefox */
    -ms-overflow-style: none;    /* IE / legacy Edge */
}
.sidebar__scroll::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* Sidebar search — prototype .sb__search: a bordered-bottom row pinned
 * between the brand and the scrolling nav, with a leading search glyph
 * and a trailing ⌘K hint. */
.sidebar__search {
    flex-shrink: 0;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border-light);
}
.sidebar__search-wrap {
    position: relative;
}
.sidebar__search-icon {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    color: var(--text-dim);
    pointer-events: none;
}
.sidebar__search-input {
    width: 100%;
    height: 34px;
    background: var(--bg-input);
    color: var(--text-strong);
    border: 1px solid var(--border);
    border-radius: var(--shell-radius-md);
    padding: 0 34px 0 32px;
    font-size: 13.5px;
}
.sidebar__search-input::placeholder { color: var(--text-dim); }
.sidebar__search-input:focus {
    outline: none;
    border-color: var(--acc);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 22%, transparent);
}
.sidebar__search-kbd {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    font: 600 10px/1 var(--font-mono);
    color: var(--text-dim);
    background: var(--bg-elevated);
    border: 1px solid var(--border-light);
    padding: 3px 5px;
    border-radius: 4px;
    pointer-events: none;
}
.app-shell[data-sidebar-collapsed="1"] .sidebar__search { display: none; }

.sidebar__section {
    margin-bottom: 0;
    position: relative;   /* positioning context for the section pin */
}
/* Prototype spacing — gap only BETWEEN sections, none after the last. */
.sidebar__section + .sidebar__section {
    margin-top: 14px;
}

/* Nav customization v2: per-section accent (2026-05-26).
 * --section-accent is set inline as `style="--section-accent: <color>"` by
 * the app_shell renderer when an admin assigns a color in Site Settings →
 * Navigation. We render it as a 3px left-edge strip on the section, plus a
 * subtle tint on the section icon. The strip is inside the section's
 * positioning context so it lines up with the heading + items vertically.
 * No accent → no rule fires (the var is undefined; everything is opt-in). */
.sidebar__section--accent {
    --section-accent-fade: color-mix(in srgb, var(--section-accent) 20%, transparent);
    padding-left: 6px;   /* room for the 3px strip without overlapping content */
}
.sidebar__section--accent::before {
    content: "";
    position: absolute;
    left: 0;
    top: 4px;
    bottom: 4px;
    width: 3px;
    border-radius: 2px;
    background: var(--section-accent);
    pointer-events: none;
}
.sidebar__section--accent > .sidebar__heading .sidebar__heading-icon {
    color: var(--section-accent);
}
.sidebar__section--accent.sidebar__section--brand > .sidebar__heading .sidebar__heading-icon {
    /* Branded sections override the icon stroke from currentColor; give
     * the accent a slightly stronger hand to keep visual weight. */
    stroke: var(--section-accent);
    color: var(--section-accent);
}

/* Custom-link items (added via the builder's "+ Add link" button) — tiny
 * visual differentiator so admins can spot external URLs at a glance.
 * The arrow-out badge sits at the trailing edge, matching the kbd hint
 * column width so layout doesn't shift between item types. */
.sidebar__item--custom-link::after {
    content: "↗";
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 11px;
    color: var(--text-dim);
    opacity: 0.6;
    pointer-events: none;
}
.sidebar__item--custom-link:hover::after { opacity: 0.95; }
/* Section heading — now a full-width collapse toggle <button>. The
 * plain (non-branded) variant keeps the prototype's tiny uppercase
 * caption look; the chevron sits at the right edge. */
.sidebar__heading {
    display: flex;
    align-items: center;
    gap: 7px;
    width: 100%;
    font: 700 10.5px/1 var(--font-display);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-dim);
    padding: 6px 8px;
    margin: 0;
    user-select: none;
    background: transparent;
    border: 0;
    border-radius: var(--shell-radius-sm);
    cursor: pointer;
    text-align: left;
    transition: background var(--shell-motion-fast) var(--shell-easing),
                color var(--shell-motion-fast) var(--shell-easing);
}
.sidebar__heading:hover {
    background: var(--bg-hover);
    color: var(--text-soft);
}
.sidebar__heading:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--brand-secondary);
}
.sidebar__heading-label {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sidebar__heading-icon {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
}
/* Chevron rotates from "open" (pointing down) to "closed" (pointing
 * right) when the section is collapsed. */
.sidebar__heading-chev {
    flex-shrink: 0;
    color: var(--text-dim);
    transition: transform var(--shell-motion-base) var(--shell-easing);
}
.sidebar__section[data-collapsed="1"] .sidebar__heading-chev {
    transform: rotate(-90deg);
}

/* Branded hero zones — TechStack + ShowReady. A tint band, a section
 * icon, and a slightly larger non-uppercase label so the two read as
 * the primary navigation zones above the plain Inventory/People/Admin
 * headings. */
.sidebar__section--brand > .sidebar__heading {
    font: 700 12px/1.2 var(--font-display);
    text-transform: none;
    letter-spacing: 0.005em;
    color: var(--text-strong);
    padding: 8px 10px;
    margin-bottom: 2px;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--acc) 13%, transparent),
        color-mix(in srgb, var(--acc) 6%, transparent));
    border: 1px solid color-mix(in srgb, var(--acc) 16%, transparent);
}
.sidebar__section--brand > .sidebar__heading:hover {
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--acc) 20%, transparent),
        color-mix(in srgb, var(--acc) 10%, transparent));
    color: var(--text-strong);
}
.sidebar__section--brand > .sidebar__heading .sidebar__heading-icon {
    width: 16px;
    height: 16px;
    color: var(--acc-2);
}
.sidebar__section--brand > .sidebar__heading .sidebar__heading-chev {
    color: var(--acc-2);
}

/* ── Section pin ──────────────────────────────────────────────────────
 * A small pin button absolutely placed in the heading row, just left of
 * the collapse chevron. Visible ONLY while the section is expanded
 * (data-collapsed absent). Clicking it pins the section open so the
 * accordion won't collapse it when another section is opened. */
.sidebar__pin {
    position: absolute;
    top: 2px;
    right: 30px;
    display: none;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: var(--shell-radius-sm);
    color: var(--text-dim);
    cursor: pointer;
    transition: background var(--shell-motion-fast) var(--shell-easing),
                color var(--shell-motion-fast) var(--shell-easing);
}
.sidebar__section--brand .sidebar__pin { top: 6px; right: 34px; }
/* Pin shows only while the section is open. */
.sidebar__section:not([data-collapsed="1"]) .sidebar__pin { display: flex; }
.sidebar__pin:hover {
    background: var(--bg-hover);
    color: var(--text-soft);
}
.sidebar__pin:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--brand-secondary);
}
.sidebar__pin-icon {
    width: 13px;
    height: 13px;
    transition: transform var(--shell-motion-fast) var(--shell-easing);
}
/* Pinned — accent the pin, a soft tint, and tip the head like a stuck pin. */
.sidebar__section[data-pinned="1"] .sidebar__pin {
    color: var(--brand-secondary);
    background: color-mix(in srgb, var(--brand-secondary) 14%, transparent);
}
.sidebar__section[data-pinned="1"] .sidebar__pin:hover {
    background: color-mix(in srgb, var(--brand-secondary) 24%, transparent);
}
.sidebar__section[data-pinned="1"] .sidebar__pin-icon {
    transform: rotate(-40deg);
}
/* Icon-rail mode hides the headings entirely → no pins either. */
.app-shell[data-sidebar-collapsed="1"] .sidebar__pin { display: none !important; }

/* Collapse mechanism — a height-animated wrapper around the item list.
 * JS sets an explicit pixel height to animate; default (no inline
 * height) lets the list size naturally. overflow:hidden clips the list
 * during the transition. */
.sidebar__collapse {
    overflow: hidden;
    transition: height var(--shell-motion-base) var(--shell-easing);
}
@media (prefers-reduced-motion: reduce) {
    .sidebar__collapse { transition: none; }
}

/* Bare section — items rendered as top-level standalone links (no
 * heading, no pin, no collapse). Produced by the Navigation builder
 * when a section's label is left blank so an item can sit on its own
 * outside any parent tree. Never collapses; always visible. */
.sidebar__section--bare > .sidebar__collapse {
    height: auto !important;
    overflow: visible;
}
.sidebar__section--bare + .sidebar__section,
.sidebar__section + .sidebar__section--bare {
    margin-top: 4px;
}

/* Jobs hub emphasis — one clear cue pair: a heavier weight + a hairline
 * divider beneath the row so "Jobs" reads as the head of the TechStack
 * zone without competing decoration. The doubled `.sidebar__item`
 * selector lifts specificity above the `.sidebar__item` font shorthand
 * (which would otherwise reset the weight back to 500). */
.sidebar__item.sidebar__item--hub,
.sidebar__item.sidebar__item--hub .sidebar__label {
    font-weight: 700;
}
.sidebar__section .sidebar__list > li:has(.sidebar__item--hub) {
    border-bottom: 1px solid var(--border-light);
    padding-bottom: 3px;
    margin-bottom: 3px;
}

/* Collapsed icon-rail: sections can't meaningfully collapse when the
 * sidebar itself is a 104px icon rail — there's no heading to click.
 * Degrade gracefully: hide the heading chrome, and always show the
 * item list regardless of any per-section collapsed flag. */
.app-shell[data-sidebar-collapsed="1"] .sidebar__heading {
    opacity: 0;
    height: 1px;
    padding: 0;
    overflow: hidden;
    pointer-events: none;
}
.app-shell[data-sidebar-collapsed="1"] .sidebar__section--brand > .sidebar__heading {
    border: 0;
    background: none;
}
.app-shell[data-sidebar-collapsed="1"] .sidebar__collapse {
    height: auto !important;
    overflow: visible;
}

.sidebar__list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.sidebar__item {
    display: flex;
    align-items: center;
    gap: 10px;
    /* CD `.sb__it` — content-height rows on 7px/10px padding, not a fixed
     * 40px row. Keeps the nav tight to match the prototype density. */
    padding: 7px 10px;
    margin: 1px 0;
    border-radius: 8px;
    color: var(--text-soft);
    font: 500 13.5px/1 var(--font-body);
    text-decoration: none;
    position: relative;
    transition: background var(--shell-motion-fast) var(--shell-easing),
                color var(--shell-motion-fast) var(--shell-easing);
    cursor: pointer;
    white-space: nowrap;
}
.sidebar__item:hover, .sidebar__item:focus-visible {
    background: var(--bg-hover);
    color: var(--text-strong);
    outline: none;
}
.sidebar__item:focus-visible {
    box-shadow: 0 0 0 2px var(--brand-secondary);
}
.sidebar__item.is-active {
    color: var(--text-strong);
    background: color-mix(in srgb, var(--acc) 14%, transparent);
}
.sidebar__item.is-active::before {
    content: "";
    position: absolute;
    left: -10px;
    top: 6px;
    bottom: 6px;
    width: 3px;
    background: linear-gradient(180deg, var(--acc-2), var(--acc));
    border-radius: 0 3px 3px 0;
}
.sidebar__icon {
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.sidebar__label {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* kbd-pill — keyboard jump-hint at the right edge of each row. Kit ships
 * these on rows that declare a `jump` letter (e.g. "G H" for Home). */
.sidebar__kbd {
    font: 600 10px/1 var(--font-mono);
    color: var(--text-dim);
    background: var(--bg-elevated);
    border: 1px solid var(--border-light);
    padding: 2px 5px;
    border-radius: 4px;
    flex-shrink: 0;
}
.app-shell[data-sidebar-collapsed="1"] .sidebar__label,
.app-shell[data-sidebar-collapsed="1"] .sidebar__kbd,
.app-shell[data-sidebar-collapsed="1"] .sidebar__badge { display: none; }

.sidebar__badge {
    background: var(--brand-secondary);
    color: var(--text-onbrand);
    font: 700 10px/1 var(--font-display);
    padding: 2px 6px;
    border-radius: 10px;
    min-width: 18px;
    text-align: center;
    flex-shrink: 0;
}
.sidebar__badge--soon {
    background: var(--bg-muted, rgba(120, 130, 150, 0.18));
    color: var(--text-soft, #8892a6);
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.sidebar__item.is-disabled {
    opacity: 0.55;
    cursor: not-allowed;
}
.sidebar__item.is-disabled:hover,
.sidebar__item.is-disabled:focus {
    background: transparent;
    color: inherit;
}

/* Collapsed tooltip — pure-CSS reveal on hover/focus of the row */
.app-shell[data-sidebar-collapsed="1"] .sidebar__item {
    justify-content: center;
    padding: 0;
}
/* (legacy CSS-only ::after tooltip removed — see .sidebar-tooltip
 * (JS-driven, anchored to sidebar.right) for the live implementation.) */

/* ── Sidebar separator (nav customization v2 — separator items) ───────
 *
 * Visual divider added by the nav-builder. Non-clickable <li> with a
 * pair of ::before/::after pseudo-elements rendering the rule on either
 * side of an optional caption.
 *
 * Styling tokens carried via inline CSS vars from the renderer:
 *   --sep-color      — null/missing falls back to var(--text-dim) so the
 *                      divider sits on top of the sidebar quietly.
 *   --sep-thickness  — pixel height of the rule (1-6 px).
 *
 * Style variants (one class per visual): --line, --double, --dashed,
 * --dotted, --space. The "space" variant suppresses the rule entirely
 * and just emits vertical padding so admins can use it as breathing
 * room. --no-label tweaks padding when there's no caption text. */
.sidebar__separator {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    margin: 4px 0;
    font: 700 10px/1 var(--font-display, var(--font-body));
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--sep-color, var(--text-dim));
    list-style: none;
    pointer-events: none;
    user-select: none;
}
.sidebar__separator::before,
.sidebar__separator::after {
    content: '';
    flex: 1 1 auto;
    height: var(--sep-thickness, 1px);
    background: currentColor;
    border-radius: 1px;
}
.sidebar__separator--line::before,
.sidebar__separator--line::after {
    background: currentColor;
    border: 0;
}
.sidebar__separator--double::before,
.sidebar__separator--double::after {
    background: none;
    border-top: var(--sep-thickness, 1px) solid currentColor;
    border-bottom: var(--sep-thickness, 1px) solid currentColor;
    height: calc((var(--sep-thickness, 1px) * 2) + 2px);
}
.sidebar__separator--dashed::before,
.sidebar__separator--dashed::after {
    background: none;
    border-top: var(--sep-thickness, 1px) dashed currentColor;
    height: 0;
}
.sidebar__separator--dotted::before,
.sidebar__separator--dotted::after {
    background: none;
    border-top: calc(var(--sep-thickness, 1px) + 1px) dotted currentColor;
    height: 0;
}
.sidebar__separator--space {
    padding: 10px 12px;
}
.sidebar__separator--space::before,
.sidebar__separator--space::after {
    display: none;
}
.sidebar__separator--no-label {
    padding: 6px 12px;
}
.sidebar__separator-label {
    flex: 0 0 auto;
    padding: 0 2px;
    white-space: nowrap;
}
/* Collapsed sidebar: drop the caption, keep the rule centered so the
 * divider still reads as a divider on the icon-only rail. */
.app-shell[data-sidebar-collapsed="1"] .sidebar__separator { padding: 6px 8px; }
.app-shell[data-sidebar-collapsed="1"] .sidebar__separator-label { display: none; }
.app-shell[data-sidebar-collapsed="1"] .sidebar__separator--space { padding: 8px; }

/* Sidebar footer — prototype .sb__foot: a "What's new" link (with the
 * live version chip) stacked above a user card. */
.sidebar__footer {
    flex-shrink: 0;
    padding: 10px;
    border-top: 1px solid var(--border-light);
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.sidebar__footer-link {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 10px;
    border-radius: var(--shell-radius-sm);
    color: var(--text-soft);
    font: 500 12.5px/1 var(--font-body);
    text-decoration: none;
    transition: background var(--shell-motion-fast) var(--shell-easing),
                color var(--shell-motion-fast) var(--shell-easing);
}
.sidebar__footer-link:hover, .sidebar__footer-link:focus-visible {
    background: var(--bg-hover);
    color: var(--text-strong);
    outline: none;
}
.sidebar__footer-icon { width: 16px; height: 16px; flex-shrink: 0; }
.sidebar__footer-link-label { flex: 1 1 auto; }
.sidebar__footer-ver {
    font: 700 10px/1 var(--font-display);
    color: var(--acc-2);
    background: color-mix(in srgb, var(--acc) 16%, transparent);
    padding: 3px 6px;
    border-radius: 999px;
    flex-shrink: 0;
}
.sidebar__user {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px;
    margin-top: 8px;
    background: var(--bg-elevated);
    border-radius: var(--shell-radius-md);
}
.sidebar__user-av {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--brand-secondary);
    color: var(--text-onbrand);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font: 700 12px/1 var(--font-display);
}
.sidebar__user-info { flex: 1 1 auto; min-width: 0; }
.sidebar__user-name {
    font: 600 13px/1.3 var(--font-body);
    color: var(--text-strong);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sidebar__user-role { font: 500 11.5px/1.3 var(--font-body); color: var(--text-dim); }
.sidebar__user-more {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-soft);
    border-radius: var(--shell-radius-sm);
    transition: background var(--shell-motion-fast) var(--shell-easing),
                color var(--shell-motion-fast) var(--shell-easing);
}
.sidebar__user-more:hover, .sidebar__user-more:focus-visible {
    background: var(--bg-hover);
    color: var(--text-strong);
    outline: none;
}
/* Tiny product/tenant/year line below the user card — replaces the legacy
 * <footer class="sr-footer"> band that used to sit below the shell. One
 * short line, dim, ellipsizes on narrow sidebars. (dev-build-72) */
.sidebar__credit {
    margin-top: 8px;
    padding: 0 4px;
    font: 500 10.5px/1.3 var(--font-body);
    color: var(--text-dim);
    text-align: center;
    word-break: break-word;
}
/* Two explicit credit lines — block-display each so they wrap to the
 * shape Carl asked for: "ShowHelm — Carl Brothers" on line 1,
 * "DigitalKaos — 2026" on line 2. */
.sidebar__credit-line { display: block; }
.sidebar__credit-link {
    color: inherit;
    text-decoration: none;
}
.sidebar__credit-link:hover, .sidebar__credit-link:focus-visible {
    color: var(--text-soft);
    text-decoration: underline;
}

/* Collapsed (icon-rail) — footer shrinks to the avatar + link glyphs. */
.app-shell[data-sidebar-collapsed="1"] .sidebar__footer-link-label,
.app-shell[data-sidebar-collapsed="1"] .sidebar__footer-ver,
.app-shell[data-sidebar-collapsed="1"] .sidebar__user-info,
.app-shell[data-sidebar-collapsed="1"] .sidebar__user-more,
.app-shell[data-sidebar-collapsed="1"] .sidebar__credit { display: none; }
.app-shell[data-sidebar-collapsed="1"] .sidebar__footer-link { justify-content: center; }
.app-shell[data-sidebar-collapsed="1"] .sidebar__user { justify-content: center; }

/* ───────── Topbar ───────── */
#app-topbar {
    grid-area: topbar;
    position: sticky;
    top: 0;
    z-index: var(--shell-z-topbar);
    height: var(--shell-topbar-h);
    background: color-mix(in srgb, var(--bg-card) 88%, transparent);
    backdrop-filter: blur(18px) saturate(120%);
    -webkit-backdrop-filter: blur(18px) saturate(120%);
    border-bottom: 1px solid var(--border-light);
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 16px;
}

.topbar__hamburger {
    display: none;
    background: transparent;
    border: 0;
    color: var(--text-primary);
    height: 36px;
    width: 36px;
    border-radius: var(--shell-radius-sm);
    cursor: pointer;
    align-items: center;
    justify-content: center;
}
.topbar__hamburger:hover, .topbar__hamburger:focus-visible {
    background: var(--bg-hover);
    outline: none;
}

/* Topbar breadcrumb — prototype .adm__tb__crumb: a single horizontal
 * "Section › Page" path with the last segment strong. The last segment
 * is the page <h1> so the document still has a heading for a11y. */
.topbar__crumb {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    flex: 0 1 auto;
    color: var(--text-soft);
    font-size: 13px;
}
.topbar__crumb-seg {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.topbar__crumb-seg--last {
    color: var(--text-strong);
    font: 600 13px/1.2 var(--font-display);
    margin: 0;
}
.topbar__crumb-sep {
    color: var(--text-dim);
    opacity: .5;
    flex-shrink: 0;
}
@media (max-width: 720px) {
    .topbar__crumb-seg:not(.topbar__crumb-seg--last),
    .topbar__crumb-sep { display: none; }
}

.topbar__center {
    flex: 1 1 auto;
    max-width: 420px;
    display: flex;
}
.topbar__search {
    width: 100%;
    position: relative;
}
.topbar__search input {
    width: 100%;
    height: 32px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-light);
    border-radius: var(--shell-radius-md);
    color: var(--text-primary);
    padding: 0 36px 0 32px;
    font-size: 13px;
}
.topbar__search input::placeholder { color: var(--text-dim); }
.topbar__search input:hover { border-color: var(--border); }
.topbar__search input:focus {
    outline: none;
    border-color: var(--acc);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 22%, transparent);
}
.topbar__search-icon {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-dim);
    pointer-events: none;
}
.topbar__search-kbd {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    background: var(--bg-elevated);
    color: var(--text-soft);
    font-size: 11px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    padding: 2px 4px;
    border-radius: 4px;
    border: 1px solid var(--border-light);
    pointer-events: none;
}

.topbar__right {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    margin-left: auto;
}
/* Primary "New deal" action — prototype .adm__tb__actions .btn--primary.
 * Gradient fill from the accent tokens; collapses to icon-only on phones. */
.topbar__newdeal {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 32px;
    padding: 0 12px;
    margin-left: 2px;
    border-radius: var(--shell-radius-md);
    background: linear-gradient(180deg, var(--acc-2) 0%, var(--acc) 100%);
    color: #fff;
    border: 1px solid color-mix(in srgb, var(--acc) 60%, #000);
    font: 600 13px/1 var(--font-body);
    white-space: nowrap;
    box-shadow: 0 1px 0 rgba(255, 255, 255, .15) inset, 0 1px 2px rgba(15, 25, 35, .18);
    transition: filter var(--shell-motion-fast) var(--shell-easing),
                transform var(--shell-motion-fast) var(--shell-easing);
}
.topbar__newdeal:hover { filter: brightness(1.06); transform: translateY(-1px); }
.topbar__newdeal:active { transform: translateY(0.5px); }
.topbar__newdeal svg { flex-shrink: 0; }
@media (max-width: 720px) {
    .topbar__newdeal { padding: 0; width: 32px; justify-content: center; }
    .topbar__newdeal span { display: none; }
}
.topbar__iconbtn {
    background: transparent;
    border: 0;
    color: var(--text-soft);
    height: 36px;
    width: 36px;
    border-radius: var(--shell-radius-sm);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    position: relative;
    transition: background var(--shell-motion-fast) var(--shell-easing),
                color var(--shell-motion-fast) var(--shell-easing);
}
.topbar__iconbtn:hover, .topbar__iconbtn:focus-visible {
    background: var(--bg-hover);
    color: var(--text-primary);
    outline: none;
}
.topbar__iconbtn:focus-visible {
    box-shadow: 0 0 0 2px var(--brand-secondary);
}
.topbar__badge {
    position: absolute;
    top: 4px;
    right: 4px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    background: var(--danger);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}
/* Kit-style unread dot — single small red dot at the top-right of an
 * icon button (no count text). Use when "something is here" is the only
 * signal needed. The wider .topbar__badge keeps the count case. */
.topbar__iconbtn-dot {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--danger);
    border: 2px solid var(--bg-card);
    pointer-events: none;
}
.topbar__avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--brand-primary);
    color: var(--text-onbrand);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    border: 1px solid var(--border-light);
    cursor: pointer;
}

/* Chrome agent's earlier non-BEM topbar menu deleted 1.61.1.5 —
   replaced by the BEM .topbar__menu-* block at end of file. */

/* ───────── Section stepper (secondary contextual nav) ─────────
 * A thin strip under the topbar showing every page in the active
 * sidebar section as → -separated pills, current page highlighted.
 * Pattern: contextual sub-tabs as a slim secondary nav
 * strip — segmented pills, sticky, horizontal-scroll with a soft
 * fade-edge mask when the section overflows (TechStack ~10 items).
 * Height is ≈ half the topbar (--shell-stepper-h). */
#app-stepper {
    grid-area: stepper;
    position: sticky;
    top: var(--shell-topbar-h);
    z-index: calc(var(--shell-z-topbar) - 1);
    height: var(--shell-stepper-h);
    /* Subtly offset from the page surface in BOTH theme modes. Nudging
     * the surface a few % toward the foreground colour guarantees a
     * perceptible-but-quiet step regardless of theme: it goes slightly
     * darker on light themes, slightly lighter on dark ones, since
     * --text-strong always contrasts --bg-card. */
    background: color-mix(in srgb, var(--bg-card) 94%, var(--text-strong) 6%);
    border-bottom: 1px solid var(--border-light);
    display: flex;
    align-items: stretch;
    overflow: hidden;
}
/* No active section resolved (e.g. a deep page with no nav match) —
 * collapse the strip so it doesn't leave an empty band. */
#app-stepper[data-empty] {
    display: none;
}
.app-stepper__strip {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 14px;
}
.app-stepper__strip[hidden] { display: none; }

/* Section label lead-in — quiet, uppercase group label. */
.app-stepper__section {
    flex: 0 0 auto;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-soft);
    padding-right: 10px;
    border-right: 1px solid var(--border-light);
    white-space: nowrap;
}

/* The scrollable track. A fade-edge mask hints at off-screen pills
 * when the section overflows; the scrollbar itself is hidden so the
 * strip stays ≈half-topbar tall. */
.app-stepper__track {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 4px;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -ms-overflow-style: none;
    -webkit-overflow-scrolling: touch;
    mask-image: linear-gradient(to right,
        transparent 0, #000 14px, #000 calc(100% - 22px), transparent 100%);
    -webkit-mask-image: linear-gradient(to right,
        transparent 0, #000 14px, #000 calc(100% - 22px), transparent 100%);
    /* a touch of scroll padding so a focused/scrolled-to pill clears
     * the fade mask edges */
    scroll-padding-inline: 24px;
}
.app-stepper__track::-webkit-scrollbar { display: none; }

/* A step pill. Compact, on-theme, hover lifts the background. */
.app-stepper__btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 20px;
    padding: 0 9px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    color: var(--text-soft);
    text-decoration: none;
    transition: background var(--shell-motion-fast) var(--shell-easing),
                color var(--shell-motion-fast) var(--shell-easing);
}
.app-stepper__btn:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
    text-decoration: none;
}
.app-stepper__btn.is-active {
    background: var(--brand-secondary);
    color: var(--text-onbrand);
}
.app-stepper__btn.is-active:hover {
    background: var(--brand-secondary);
    color: var(--text-onbrand);
}
.app-stepper__btn:focus-visible {
    outline: 2px solid var(--brand-accent);
    outline-offset: 1px;
}
.app-stepper__btn.is-disabled {
    color: var(--text-soft);
    opacity: 0.5;
    cursor: default;
    pointer-events: none;
}

/* "Soon" / "Locked" badge carried over from the sidebar item. */
.app-stepper__badge {
    font-size: 8.5px;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    padding: 1px 5px;
    border-radius: 999px;
    background: var(--bg-input);
    color: var(--text-soft);
    border: 1px solid var(--border-light);
}
.app-stepper__btn.is-active .app-stepper__badge {
    background: color-mix(in srgb, var(--text-onbrand) 22%, transparent);
    color: var(--text-onbrand);
    border-color: transparent;
}

/* The → between consecutive steps — a workflow-stepper cue. */
.app-stepper__arrow {
    flex: 0 0 auto;
    color: var(--text-soft);
    opacity: 0.55;
}

/* Mobile (< 768px): the app already has a bottom-tab bar; the stepper
 * would crowd a narrow viewport, so hide it there. Tablet keeps it. */
@media (max-width: 767.98px) {
    #app-stepper { display: none; }
}

/* ───────── Content ─────────
 * #app-content is the ONLY scroll container in the v2 shell — html + body
 * + .app-shell are all locked to 100dvh + overflow:hidden above, so any
 * tall page content scrolls here while the sidebar + topbar stay pinned.
 * overscroll-behavior:contain stops a top/bottom bounce from bubbling up
 * to the (locked) body and triggering iOS Safari's URL-bar gymnastics. */
#app-content {
    grid-area: content;
    min-width: 0;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding: 24px;
    /* Establish a containing block so the scoped loading overlay
     * (.sr-loading-overlay--scoped, position:absolute) clips to just
     * the main window — chrome stays sharp. */
    position: relative;
}
#app-content.with-rightpane {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 24px;
}
#app-rightpane {
    border-left: 1px solid var(--border-light);
    padding-left: 16px;
}

/* ───────── Mobile drawer / backdrop ───────── */
.app-shell__backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.7);
    z-index: var(--shell-z-backdrop);
}
.app-shell[data-mobile-drawer="1"] .app-shell__backdrop { display: block; }

@media (max-width: 1023.98px) {
    .app-shell,
    .app-shell[data-sidebar-collapsed="1"] {
        /* Both branches must explicitly use a single column on mobile.
         * Without the [data-sidebar-collapsed="1"] override here, that
         * higher-specificity selector keeps the desktop 64px+1fr grid
         * active on mobile and squeezes main content to a 64px sliver
         * behind a phantom sidebar gutter. (Bug #1, sitewide CSS sweep.) */
        grid-template-columns: 1fr;
        grid-template-areas:
            "topbar"
            "stepper"
            "content";
    }
    #app-sidebar,
    .app-sidebar {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        width: var(--shell-sidebar-w);
        transform: translateX(-100%);
        transition: transform var(--shell-motion-base) var(--shell-easing);
        z-index: var(--shell-z-drawer);
    }
    .app-shell[data-mobile-drawer="1"] #app-sidebar,
    .app-shell[data-mobile-drawer="1"] .app-sidebar {
        transform: translateX(0);
    }
    .topbar__hamburger { display: inline-flex; }
    #app-content.with-rightpane {
        grid-template-columns: 1fr;
    }
    #app-rightpane {
        border-left: 0;
        padding-left: 0;
        border-top: 1px solid var(--border-light);
        padding-top: 16px;
    }
}

/* ───────── Bottom-tab bar (mobile only) ───────── */
/* The .app-bottomtabs class (applied to #app-bottombar-mount in markup)
 * provides all the layout rules. Don't add a #app-bottombar-mount
 * display:none here — ID specificity (0,1,0,0) beats the class
 * (0,0,1,0) and would suppress the tabs entirely. */
@media (max-width: 767.98px) {
    /* #app-bottombar-mount placeholder rule removed 1.61.3.2 —
     * .app-bottomtabs (the class my emit lives on) provides display:grid
     * + position/z-index. Old ID rule had display:block which beat the
     * class on specificity, causing tabs to clump left. */
    #app-content {
        padding-bottom: calc(var(--shell-bottombar-h) + 16px);
    }
}

/* Placeholder for the bottom bar while the JS island hydrates — keeps
   the bar from popping in awkwardly. The Mobile UX agent owns the
   actual <mobile-bottombar> Svelte mount; this is the shell scaffold. */
.bottombar-placeholder {
    display: flex;
    justify-content: space-around;
    align-items: center;
    height: 100%;
    color: var(--text-soft);
}
.bottombar-placeholder .tab {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    font-size: 10px;
    color: var(--text-soft);
    text-decoration: none;
    padding: 6px 10px;
    flex: 1 1 0;
    text-align: center;
}
.bottombar-placeholder .tab svg { width: 20px; height: 20px; stroke: currentColor; fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.bottombar-placeholder .tab.is-active { color: var(--brand-accent); }

/* ───────── View Transitions ───────── */
/* Stagger sidebar nav transitions so navigating between sections fades
   smoothly when the browser supports the View Transitions API. */
@supports (view-transition-name: none) {
    .sidebar__item { view-transition-name: var(--vt-name, none); }
}

/* ───────── Density tuning ───────── */
@media (max-width: 1280px) {
    #app-content { padding: 18px; }
}
@media (max-width: 640px) {
    #app-content { padding: 14px; }
    .topbar__title { font-size: 14px; }
    .topbar__center { display: none; } /* search collapses to icon-only on phone */
}

/* ───────── 1.61.0.0 — legacy taskbar kill-switch ─────────
 * The XP-style #shell-taskbar / .shell-startmenu markup is no longer
 * emitted by portal_shell_taskbar(), but this rule defends against any
 * stale code path (e.g. cached pages, third-party embed, future
 * re-enable mistake) that would resurrect it. Also drops the body
 * padding-bottom that legacy code injected to reserve taskbar space.
 */
#shell-taskbar, .shell-taskbar, .shell-startmenu { display: none !important; }
body.shell-mode-classic, body.shell-taskbar-on { padding-bottom: 0 !important; }

/* Many admin pages emit their own `<main class="page">` inside our
 * `#app-content main` slot. The outer `<main>` already controls width and
 * padding. Reset the inner one so it doesn't double up. */
#app-content main.page { max-width: none; margin: 0; padding: 0; }
#app-content .app-content__main { display: block; min-height: 0; }

/* Default content padding (overridden by the responsive blocks above). */
#app-content { padding: 24px; }

/* Compatibility: the legacy `.topbar` and friends used to live at the
 * page root. They're now retired; if they appear (e.g. someone calls
 * _portal_admin_topbar_legacy()) hide them so the v2 chrome wins. */
header.topbar--admin, header.topbar--worker { display: none; }

/* Theme toggle inside the new topbar: align it like the icon buttons.
 * <theme-toggle compact> renders its own shadow-DOM; we control the
 * outer host with these rules. */
#app-topbar theme-toggle {
    display: inline-flex;
    align-items: center;
    height: 36px;
}

/* Sidebar contrast: the design prototype puts the sidebar on --bg-card
 * and lets the theme tokens (--text-strong/-soft/-dim, --bg-elevated,
 * --acc) flip it per theme. The base .sidebar__* rules above are fully
 * tokenized, so no per-theme override block is needed — light/dim/dark
 * all resolve correctly from the tokens. (Removed the old force-white
 * block that assumed a permanently-dark --bg-topbar sidebar.) */

/* ─────────────────────────────────────────────────────────────
 * Topbar avatar dropdown menu (Section 1, 1.61.1.5)
 *
 * Built from kit primitives — uses --shell-radius-md/-lg,
 * --shell-easing, --bg-card, --bg-hover, --border,
 * --shadow-card-lg, --text-strong/--soft, --danger-ink.
 * The kit's components.jsx doesn't define a dropdown component,
 * but the design vocabulary (radii, easing, surface tokens) is
 * established. Used by the avatar in <header id="app-topbar">.
 * ─────────────────────────────────────────────────────────── */
.topbar__avatar-wrap {
  position: relative;
}

.topbar__avatar {
  cursor: pointer;
}

.topbar__menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 240px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--shell-radius-lg, 12px);
  box-shadow: var(--shadow-card-lg);
  padding: 6px;
  z-index: var(--shell-z-dropdown, 65);
  opacity: 0;
  transform: translateY(-4px) scale(.98);
  transform-origin: top right;
  transition: opacity var(--shell-motion-base, 200ms) var(--shell-easing, cubic-bezier(0.4, 0, 0.2, 1)),
              transform var(--shell-motion-base, 200ms) var(--shell-easing, cubic-bezier(0.4, 0, 0.2, 1));
  pointer-events: none;
}

.topbar__menu:not([hidden]) {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

.topbar__menu-identity {
  padding: 10px 12px 8px;
}

.topbar__menu-name {
  font: 600 14px/1.2 var(--font-display, 'Inter', sans-serif);
  color: var(--text-strong);
}

.topbar__menu-email {
  font: 500 12px/1.4 var(--font-body, 'Inter', sans-serif);
  color: var(--text-soft);
  margin-top: 2px;
  word-break: break-all;
}

.topbar__menu-divider {
  height: 1px;
  background: var(--border-light, var(--border));
  margin: 4px 0;
}

.topbar__menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-radius: var(--shell-radius-md, 8px);
  font: 500 13px/1.2 var(--font-body, 'Inter', sans-serif);
  color: var(--text-strong);
  text-decoration: none;
  cursor: pointer;
  border: 0;
  background: transparent;
  width: 100%;
  text-align: left;
  box-sizing: border-box;
  transition: background var(--shell-motion-fast, 120ms) var(--shell-easing, cubic-bezier(0.4, 0, 0.2, 1));
}

.topbar__menu-item:hover,
.topbar__menu-item:focus-visible {
  background: var(--bg-hover);
  color: var(--text-strong);
  outline: none;
  text-decoration: none;
}

.topbar__menu-item--danger {
  color: var(--danger-ink, #721c24);
}

.topbar__menu-item--danger:hover,
.topbar__menu-item--danger:focus-visible {
  background: var(--danger-soft, #fdecea);
  color: var(--danger-ink, #721c24);
}

.topbar__menu-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

@media (prefers-reduced-motion: reduce) {
  .topbar__menu,
  .topbar__menu-item {
    transition: none;
  }
}

/* Mobile: avatar sits mid-screen at narrow widths, so the
   right:0 wrapper-relative anchor would push the menu off the
   left edge. Pin it to the viewport-right + clamp width. */
@media (max-width: 768px) {
  .topbar__menu {
    position: fixed;
    top: calc(var(--shell-topbar-h, 56px) + 4px);
    right: 8px;
    left: auto;
    min-width: 240px;
    max-width: calc(100vw - 16px);
  }
}

/* ─────────────────────────────────────────────────────────────
 * Mobile drawer label fix (Section 3, 1.61.3.0)
 *
 * On phones the sidebar transforms into an off-canvas drawer. But
 * if the user previously collapsed the desktop sidebar (state
 * stored in localStorage as showhelm_sidebar_collapsed=1), the
 * `[data-sidebar-collapsed="1"]` selector still hides labels,
 * search, and section headings — so the open drawer is icons-only
 * and unreadable. Override below 1024px so the drawer always shows
 * its full content regardless of any collapsed-state attribute.
 * ─────────────────────────────────────────────────────────── */
@media (max-width: 1023.98px) {
  /* Force full sidebar width inside the drawer even when collapsed flag is on */
  .app-shell[data-sidebar-collapsed="1"] #app-sidebar,
  .app-shell[data-sidebar-collapsed="1"] .app-sidebar {
    width: var(--shell-sidebar-w, 240px);
  }
  /* Reveal every collapsed-state-hidden element inside the drawer */
  .app-shell[data-sidebar-collapsed="1"] .sidebar__label,
  .app-shell[data-sidebar-collapsed="1"] .sidebar__kbd,
  .app-shell[data-sidebar-collapsed="1"] .sidebar__badge,
  .app-shell[data-sidebar-collapsed="1"] .sidebar__heading,
  .app-shell[data-sidebar-collapsed="1"] .sidebar__search,
  .app-shell[data-sidebar-collapsed="1"] .sidebar__brand-text,
  .app-shell[data-sidebar-collapsed="1"] .sidebar__role-pill {
    display: revert;
  }
  .app-shell[data-sidebar-collapsed="1"] .sidebar__brand {
    justify-content: flex-start;
    padding: 14px 16px;
  }
  /* Hide the desktop-only collapse button inside the drawer (it doesn't
     apply to a mobile drawer that already takes the full width). */
  .app-shell[data-sidebar-collapsed="1"] .sidebar__collapse-btn,
  [data-sidebar-collapse] {
    display: none;
  }
}
@media (min-width: 1024px) {
  /* Restore: collapse button stays available on desktop. */
  [data-sidebar-collapse] {
    display: inline-flex;
  }
}

/* Hide the office-staff chat band on phones. It overlaps where the kit
 * intends a bottom tab-bar to live and dominates mobile real estate.
 * Re-introduced as a proper MBottomTabs-style nav in a follow-up. */
@media (max-width: 767.98px) {
  .sr-chat-bar,
  #srChatBar {
    display: none !important;
  }
  /* Reclaim the bottom padding sr-chat-bar took on the page. */
  body.has-chat-bar #app-content,
  body.has-chat-bar { padding-bottom: 0 !important; }
}

/* ─────────────────────────────────────────────────────────────
 * Mobile bottom tab bar (Section 3, 1.61.3.1)
 *
 * Kit MBottomTabs pattern from
 * design_ui/ui_kits/portal-mobile/mobile-shell.jsx lines 113-152.
 * Visible only on phones (≤ 767.98px). 5 equal-width tabs.
 * Active tab: --brand-secondary color + 2px accent line on top edge.
 * ─────────────────────────────────────────────────────────── */
.app-bottomtabs {
  display: none; /* desktop hidden — overridden below for phones */
}

@media (max-width: 767.98px) {
  .app-bottomtabs {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--shell-bottombar-h, 64px);
    background: var(--bg-card);
    border-top: 1px solid var(--border-light);
    padding-bottom: env(safe-area-inset-bottom, 0);
    z-index: var(--shell-z-bottombar, 55);
  }
  .app-bottomtabs__tab {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    background: transparent;
    border: 0;
    color: var(--text-soft);
    cursor: pointer;
    position: relative;
    text-decoration: none;
    padding: 0;
    transition: color var(--shell-motion-fast, 120ms) var(--shell-easing, cubic-bezier(0.4, 0, 0.2, 1));
  }
  .app-bottomtabs__tab.is-active,
  .app-bottomtabs__tab[aria-selected="true"] {
    color: var(--brand-secondary);
  }
  .app-bottomtabs__tab.is-active::before,
  .app-bottomtabs__tab[aria-selected="true"]::before {
    content: "";
    position: absolute;
    top: 0;
    left: 30%;
    right: 30%;
    height: 2px;
    background: var(--brand-secondary);
    border-radius: 0 0 2px 2px;
  }
  .app-bottomtabs__icon {
    width: 22px;
    height: 22px;
    flex-shrink: 0;
  }
  .app-bottomtabs__label {
    font: 600 10px/1 var(--font-body);
    white-space: nowrap;
  }
  /* Make content padding-bottom account for the tabs */
  #app-content {
    padding-bottom: calc(var(--shell-bottombar-h, 64px) + 16px) !important;
  }
}
@media (prefers-reduced-motion: reduce) {
  .app-bottomtabs__tab { transition: none; }
}


/* Sidebar section headings are collapse toggles (feature request #15):
 * a <button class="sidebar__heading"> with a chevron; clicking it
 * height-animates the .sidebar__collapse wrapper. State persists per
 * user in localStorage; the active page's section is force-expanded.
 * See the .sidebar__heading / .sidebar__collapse rules above for the
 * mechanics, plus the .sidebar__section--brand hero treatment. */

/* ───── Sidebar pull-tab (1.61.3.6) ─────
 * Semi-transparent half-pill protruding from the sidebar's right edge,
 * fixed to viewport vertical-center so it stays in reach as the page
 * scrolls. Toggles sidebar collapse/expand. */
.sidebar__pull-tab {
  position: fixed;
  top: 50%;
  left: var(--shell-sidebar-w, 240px);
  transform: translate(-1px, -50%);
  /* -1px so the flat left edge sits flush against the sidebar without a hairline seam. */
  width: 16px;
  height: 44px;
  border: 1px solid var(--border-light, rgba(255,255,255,.10));
  border-left: 0;
  border-radius: 0 16px 16px 0;
  background: rgba(15, 26, 38, 0.72);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
  color: rgba(255, 255, 255, 0.82);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  z-index: calc(var(--shell-z-sidebar, 40) + 1);
  box-shadow: 2px 0 8px rgba(0, 0, 0, 0.18);
  transition: left var(--shell-motion-base, 200ms) var(--shell-easing, ease),
              background var(--shell-motion-fast, 120ms) var(--shell-easing, ease),
              color var(--shell-motion-fast, 120ms) var(--shell-easing, ease);
}
.sidebar__pull-tab:hover {
  background: rgba(15, 26, 38, 0.90);
  color: #ffffff;
}
.sidebar__pull-tab:focus-visible {
  outline: 2px solid var(--brand-secondary, #5a7a9b);
  outline-offset: 2px;
}
.sidebar__pull-tab-chevron {
  transition: transform var(--shell-motion-base, 200ms) var(--shell-easing, ease);
}
.app-shell[data-sidebar-collapsed="1"] .sidebar__pull-tab {
  left: var(--shell-sidebar-w-collapsed, 64px);
}
.app-shell[data-sidebar-collapsed="1"] .sidebar__pull-tab-chevron {
  transform: rotate(180deg);
}
/* On mobile the sidebar is an off-canvas drawer, not a collapsible
 * panel — the hamburger and bottom-tab "More" button already serve
 * as open/close affordances, so hide the pull-tab there. */
@media (max-width: 1023.98px) {
  .sidebar__pull-tab { display: none; }
}
/* Light theme — slightly lighten the tab so it doesn't feel like a
 * black bar floating on pale page bg. */
[data-theme="light"] .sidebar__pull-tab {
  background: rgba(15, 26, 38, 0.62);
  color: rgba(255, 255, 255, 0.92);
}
[data-theme="light"] .sidebar__pull-tab:hover {
  background: rgba(15, 26, 38, 0.85);
}

/* ───── Icon-rail 2-column grid (1.61.3.8) ─────
 * Sleek collapsed-rail layout: icons in 2 columns with a thin
 * vertical divider down the middle of each section's list.
 * Hover spawns a floating tooltip (CSS below; positioning by JS). */
.app-shell[data-sidebar-collapsed="1"] .sidebar__list {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 0;
  row-gap: 3px;
  padding: 2px 3px;
}
.app-shell[data-sidebar-collapsed="1"] .sidebar__list > li {
  display: flex;
  justify-content: center;
  align-items: center;
}
.app-shell[data-sidebar-collapsed="1"] .sidebar__list .sidebar__item {
  width: 32px;
  height: 32px;
  padding: 0;
  justify-content: center;
  border-radius: 7px;
}
/* Hide non-icon row decorations in icon-rail mode. */
.app-shell[data-sidebar-collapsed="1"] .sidebar__list .sidebar__label,
.app-shell[data-sidebar-collapsed="1"] .sidebar__list .sidebar__kbd,
.app-shell[data-sidebar-collapsed="1"] .sidebar__list .sidebar__badge { display: none; }
/* Vertical divider between the two columns, one per section. */
.app-shell[data-sidebar-collapsed="1"] .sidebar__list::before {
  content: "";
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 50%;
  width: 1px;
  background: var(--border-light, rgba(255,255,255,.10));
  transform: translateX(-50%);
  pointer-events: none;
}
/* (dead :has() rule removed — divider was killed in 1.61.3.10.) */
/* ───── Floating tooltip bubble (icon-rail mode) ───── */
.sidebar-tooltip {
  position: fixed;
  z-index: 1000;
  transform: translateY(-50%);
  background: rgba(15, 26, 38, 0.96);
  color: #ffffff;
  font: 500 12px/1.2 var(--font-body, system-ui, sans-serif);
  padding: 6px 10px;
  border-radius: 6px;
  white-space: nowrap;
  pointer-events: none;
  border: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
  animation: sidebar-tooltip-fade-in 100ms ease-out;
}
.sidebar-tooltip[hidden] { display: none; }
.sidebar-tooltip::before {
  content: "";
  position: absolute;
  left: -5px;
  top: 50%;
  width: 0;
  height: 0;
  border: 5px solid transparent;
  border-right-color: rgba(15, 26, 38, 0.96);
  border-left: 0;
  transform: translateY(-50%);
}
@keyframes sidebar-tooltip-fade-in {
  from { opacity: 0; transform: translate(-4px, -50%); }
  to   { opacity: 1; transform: translate(0,    -50%); }
}

/* ───── Icon-rail tighten pass (1.61.3.10) ─────
 * Compact section gap, drop the per-section column divider
 * (cleaner with just the section separator), tighter brand,
 * inset-ring active state instead of off-rail left bar. */
.app-shell[data-sidebar-collapsed="1"] .sidebar__section {
  margin-bottom: 10px;
}
.app-shell[data-sidebar-collapsed="1"] .sidebar__brand {
  /* keep height inherited from --shell-topbar-h (56px) so the
   * sidebar header aligns with the topbar border-bottom. */
  padding: 0;
  justify-content: center;
}
/* Drop the column divider line — at 76 px the two icon
 * columns self-align and a vertical rule reads as noise. */
.app-shell[data-sidebar-collapsed="1"] .sidebar__list::before {
  display: none;
}
/* Hover: subtle highlight without the kit's expanded-mode pill. */
.app-shell[data-sidebar-collapsed="1"] .sidebar__item:hover {
  background: rgba(255, 255, 255, 0.06);
}
/* Active: drop the kit's off-rail ::before indicator (it bleeds
 * off the 3 px outer padding at this width) and use an inset
 * 1 px ring tinted by --brand-secondary instead. */
.app-shell[data-sidebar-collapsed="1"] .sidebar__item.is-active::before {
  display: none;
}
.app-shell[data-sidebar-collapsed="1"] .sidebar__item.is-active {
  box-shadow: inset 0 0 0 1px rgba(122, 154, 187, 0.45);
}

/* ───── Mobile drawer — kit MDrawer port (1.61.12.0) ─────
 * Off-canvas mobile drawer matching design_ui/ui_kits/portal-mobile/
 * mobile-shell.jsx MDrawer. Hidden on desktop, shown only at ≤ 1023.98 px.
 * Driven by the same [data-mobile-drawer] attribute as the old squeezed-
 * sidebar drawer; hamburger + bottom-tab "More" toggles still apply. */
.app-mobile-drawer {
  display: none;
}
@media (max-width: 1023.98px) {
  /* Mobile: hide the desktop sidebar entirely, show the kit drawer. */
  #app-sidebar, .app-sidebar { display: none !important; }
  .app-mobile-drawer {
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: min(82%, 320px);
    background: var(--bg-card, #ffffff);
    transform: translateX(-100%);
    transition: transform 260ms cubic-bezier(.2, .8, .2, 1);
    z-index: var(--shell-z-drawer, 60);
    box-shadow: 4px 0 24px rgba(0, 0, 0, 0.18);
    overflow: hidden;
  }
  .app-shell[data-mobile-drawer="1"] .app-mobile-drawer {
    transform: translateX(0);
  }
  /* Soften the backdrop on mobile per kit (was .7). */
  .app-shell__backdrop {
    background: rgba(0, 0, 0, 0.45);
  }
  /* Hide the pull-tab on mobile — drawer toggle is the topbar
   * hamburger + the bottom-tab "More" button. (Already set in
   * the pull-tab block, kept here for clarity.) */
  .sidebar__pull-tab { display: none; }
}

.app-mobile-drawer__header {
  padding: 20px 18px 16px;
  background: var(--brand-darker, #0f1a26);
  color: #ffffff;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
.app-mobile-drawer__chip {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--brand-secondary, #5a7a9b);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font: 900 italic 15px/1 var(--font-display, system-ui);
  letter-spacing: 0.02em;
  color: #ffffff;
  flex-shrink: 0;
}
.app-mobile-drawer__who {
  flex: 1;
  min-width: 0;
}
.app-mobile-drawer__name {
  font: 700 14px/1.2 var(--font-display, system-ui);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.app-mobile-drawer__sub {
  font: 500 11px/1.2 var(--font-body, system-ui);
  color: rgba(255, 255, 255, 0.7);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.app-mobile-drawer__nav {
  flex: 1;
  padding: 10px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  -webkit-overflow-scrolling: touch;
}
.app-mobile-drawer__row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 11px 14px;
  min-height: 44px;
  background: transparent;
  border: 0;
  border-radius: 10px;
  color: var(--text-strong, #0f1a26);
  text-decoration: none;
  font: 600 14px/1.15 var(--font-body, system-ui);
  transition: background 120ms var(--shell-easing, ease);
}
.app-mobile-drawer__row:hover,
.app-mobile-drawer__row:active {
  background: var(--bg-hover, rgba(0, 0, 0, 0.04));
}
.app-mobile-drawer__row.is-active {
  background: color-mix(in oklab, var(--brand-secondary, #5a7a9b) 14%, transparent);
  color: var(--brand-secondary, #5a7a9b);
}
.app-mobile-drawer__icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-soft, #5a6b7d);
}
.app-mobile-drawer__row.is-active .app-mobile-drawer__icon { color: inherit; }
.app-mobile-drawer__icon > svg,
.app-mobile-drawer__icon > img { width: 20px; height: 20px; }
.app-mobile-drawer__label {
  flex: 1;
  min-width: 0;
}

/* Group heading — small uppercase section label between row groups so the
 * full nav reads as the same Operate / Floor / Inventory / CRM grouping as
 * the desktop sidebar. Sticky so the current group label stays in view as
 * the (now full) menu scrolls. */
.app-mobile-drawer__heading {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 14px 14px 6px;
  margin-top: 4px;
  font: 700 11px/1.2 var(--font-body, system-ui);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim, #8a98a8);
  background: var(--bg-card, #ffffff);
}
.app-mobile-drawer__nav > .app-mobile-drawer__heading:first-child { margin-top: 0; }

/* Inline separator row (nav customization "separator" item). */
.app-mobile-drawer__sep {
  height: 1px;
  margin: 6px 14px;
  background: var(--border-light, rgba(0, 0, 0, 0.10));
}

/* Trailing badge (e.g. a "Locked" module marker) — sits at the row's far
 * right, muted pill so it reads as a status, not an action. */
.app-mobile-drawer__badge {
  flex-shrink: 0;
  font: 700 10px/1 var(--font-body, system-ui);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-soft, #5a6b7d);
  background: var(--bg-hover, rgba(0, 0, 0, 0.05));
  border: 1px solid var(--border-light, rgba(0, 0, 0, 0.10));
  border-radius: 999px;
  padding: 3px 7px;
}

/* Header close button — explicit dismiss affordance alongside the
 * backdrop-tap / Escape paths. */
.app-mobile-drawer__close {
  margin-left: auto;
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.08);
  border: 0;
  border-radius: 10px;
  color: rgba(255, 255, 255, 0.85);
  cursor: pointer;
  transition: background 120ms var(--shell-easing, ease);
}
.app-mobile-drawer__close:hover,
.app-mobile-drawer__close:focus-visible {
  background: rgba(255, 255, 255, 0.16);
  color: #ffffff;
  outline: none;
}

.app-mobile-drawer__footer {
  padding: 14px;
  border-top: 1px solid var(--border-light, rgba(0, 0, 0, 0.10));
  flex-shrink: 0;
}
.app-mobile-drawer__signout {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 12px 14px;
  min-height: 44px;
  background: transparent;
  border: 0;
  border-radius: 8px;
  color: var(--text-soft, #5a6b7d);
  text-decoration: none;
  font: 600 13px/1 var(--font-body, system-ui);
  transition: background 120ms var(--shell-easing, ease);
}
.app-mobile-drawer__signout:hover {
  background: var(--bg-hover, rgba(0, 0, 0, 0.04));
  color: var(--danger-ink, #c0392b);
}

/* ───── Mobile topbar right-cluster tightening (1.62.1.1) ─────
 * On narrow phones the bell + theme-toggle + avatar cluster
 * fights with the hamburger for space. Tighten gap, hide the
 * theme-toggle's chevron/menu affordance (icon-only mode), and
 * shrink the iconbutton hit slightly so the row breathes. */
@media (max-width: 480px) {
  .topbar__right { gap: 4px; }
  /* Hide the <theme-toggle>'s submenu indicator on phones. The
   * compact attribute already collapses the labels, but the
   * shadow-DOM chevron + menu chip wrapper still render. */
  theme-toggle[compact] { --tt-chevron-display: none; }
  theme-toggle[compact]::part(menu) { display: none; }
  theme-toggle[compact]::part(chevron) { display: none; }
  /* Fallback: many theme-toggle implementations don't expose
   * shadow parts. Direct-children fallback. */
  theme-toggle[compact] svg + svg { display: none; }
}
@media (max-width: 380px) {
  .topbar__right { gap: 2px; }
  .topbar__iconbtn { width: 36px; height: 36px; }
}

/* ───── Mobile bottom-tab clearance (1.62.1.14) ─────
 * On mobile (≤1023.98 px) the bottom-tab bar is position:fixed at
 * the bottom with height var(--shell-bottombar-h, 60px). Pages
 * need bottom padding so their last row isn't behind the tab bar.
 * Provide it once, here — no per-page specificity-escalation fights. */
@media (max-width: 1023.98px) {
  #app-content main.page,
  #app-content .page {
    padding-bottom: calc(var(--shell-bottombar-h, 60px) + 36px);
  }
}

/* ───── Compact desktop chrome — small-screen fit pass ─────
 * 1366×768 is now the smallest supported desktop screen. After the OS
 * taskbar + browser chrome a 768-tall display yields a real viewport
 * around 620–660 px, so vertical room is scarce. This block tightens
 * the shell chrome (topbar, stepper, content padding) on SHORT desktop
 * viewports only — ≥1024-wide so it never collides with the mobile
 * drawer rules, and height-gated so 1440/1920-tall screens keep the
 * comfortable spacing. Width is also tightened toward ~1280 so dense
 * pages degrade gracefully. Nothing here touches functionality.        */
@media (min-width: 1024px) and (max-height: 820px) {
  :root {
    --shell-topbar-h: 44px;
    --shell-stepper-h: 26px;
  }
  /* Slimmer topbar internals so the 44px height isn't cramped. */
  #app-topbar { gap: 10px; padding: 0 12px; }
  .topbar__search input { height: 30px; }
  .topbar__newdeal { height: 30px; }
  .topbar__avatar { width: 30px; height: 30px; }
  /* Stepper pills shrink a touch to sit happily in 26px. */
  .app-stepper__strip { padding: 0 12px; }
  .app-stepper__btn { height: 18px; }
  /* Reclaim vertical + horizontal room in the scroll window. */
  #app-content { padding: 16px; }
  #app-content.with-rightpane { gap: 16px; }
}

/* Very short viewports (≈1366×600-and-under, or a 768 screen with a
 * tall taskbar + bookmarks bar). Squeeze a little harder.            */
@media (min-width: 1024px) and (max-height: 660px) {
  :root { --shell-topbar-h: 42px; }
  #app-content { padding: 12px 16px; }
}

/* Narrow desktop (1024–1400) — keep the content gutter modest so wide
 * tables / the deals kanban / the role matrix have maximum usable
 * width before their own internal scroll kicks in. ≥1440 unaffected. */
@media (min-width: 1024px) and (max-width: 1400px) {
  #app-content { padding-left: 18px; padding-right: 18px; }
  #app-content.with-rightpane { grid-template-columns: minmax(0, 1fr) 300px; }
}
