/* Presentation for the UI shell (chrome) — the accent icon rail, the module-owned secondary panel, the
 * persistent top bar, content frame and footer. The rail + secondary are FIXED (non-scrolling) at every
 * width, pinned below the top bar (M-075): a single top-bar toggle drives one nav model, expressed as two
 * flags on <html> and read per breakpoint. Below 48rem they slide in as one off-canvas drawer over a
 * scrim (data-nav-open); from 48rem up they are on-screen by default and the content column is offset by
 * their width, collapsing off-screen — with the content reclaiming the width — when data-nav-collapsed is
 * set (persisted). The secondary panel is only present when the active module contributes one; when
 * absent, content clears the rail alone. Embedded mode renders no chrome at all, so the rail/secondary/
 * top-bar rules simply have nothing to style there. Every value comes from the design tokens (tokens.css)
 * so the shell is themeable without touching markup (coding-standards §4, §12).
 */

.platform-shell {
    margin: 0;
    min-height: 100vh;
    font-family: var(--platform-font-body);
    font-size: var(--platform-font-size-md);
    letter-spacing: var(--platform-letter-spacing, normal);
    color: var(--platform-color-text);
    background: var(--platform-color-page-bg, #f2f2f6);
}

/* Keyboard skip link — visually hidden until focused. */
.platform-shell__skip-link {
    position: absolute;
    left: var(--platform-space-sm);
    top: -3rem;
    z-index: 60;
    padding: var(--platform-space-xs) var(--platform-space-sm);
    background: var(--platform-color-surface);
    color: var(--platform-color-accent);
    border-radius: var(--platform-radius-sm);
    transition: top 0.15s ease;
}

.platform-shell__skip-link:focus {
    top: var(--platform-space-sm);
}

/* Brand lockup — shared markup, context-coloured (see rail/top-bar overrides below). */
.platform-shell__brand {
    display: inline-flex;
    align-items: center;
    gap: var(--platform-space-sm);
    color: inherit;
    text-decoration: none;
}

.platform-shell__brand-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: var(--platform-radius-sm);
    background: var(--platform-color-accent);
    color: var(--platform-color-on-accent);
    font-weight: 700;
}

/* ── Persistent top bar (all widths, M-075) ───────────────────────────────────────────────────
 * Holds the brand + the single nav toggle. Sticky at the top and ABOVE the mobile scrim so the toggle
 * stays clickable to dismiss the drawer. The fixed rail/subnav start just below it (top: topbar-height).
 */
.platform-shell__topbar {
    position: sticky;
    top: 0;
    z-index: 55;
    display: flex;
    align-items: center;
    gap: var(--platform-space-sm);
    height: var(--platform-topbar-height);
    padding: 0 var(--platform-space-md);
    background: var(--platform-color-surface);
    border-bottom: 1px solid var(--platform-color-border);
}

.platform-shell__nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--platform-space-xs);
    color: var(--platform-color-text);
    background: none;
    border: 1px solid var(--platform-color-border);
    border-radius: var(--platform-radius-sm);
    cursor: pointer;
}

.platform-shell__nav-toggle:hover {
    background: var(--platform-color-surface-muted);
}

.platform-shell__nav-icon {
    width: 1.25rem;
    height: 1.25rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* ── Layout: rail + secondary + content column ────────────────────────────────────────────── */
.platform-shell__layout {
    display: flex;
    align-items: stretch;
}

.platform-shell__content-col {
    display: flex;
    flex: 1;
    min-width: 0;
    flex-direction: column;
    /* The persistent top bar (all widths) sits above the layout, so fill the rest of the viewport. */
    min-height: calc(100vh - var(--platform-topbar-height));
}

/* ── Primary icon rail ────────────────────────────────────────────────────────────────────── */
/* Fixed at EVERY width, pinned below the top bar and full-height to the viewport bottom. It slides in
 * as an off-canvas drawer on mobile and collapses off-screen on desktop — the same transform, driven by
 * the nav flags on <html> in the media-scoped rules further down. Hidden (off-screen) by default here. */
.platform-rail {
    position: fixed;
    top: var(--platform-topbar-height);
    bottom: 0;
    left: 0;
    z-index: 50;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--platform-space-md);
    width: var(--platform-rail-width);
    padding: var(--platform-space-md) 0;
    /* `visible` (not `auto`) so the instant hover/focus label chips can escape the narrow rail to the
     * right. The rail holds a handful of icons, so it never needs to scroll at this scale. */
    overflow: visible;
    color: var(--platform-color-sidebar-text);
    background: linear-gradient(180deg, var(--platform-color-sidebar), var(--platform-color-sidebar-strong));
    transform: translateX(-100%);
    transition: transform 0.2s ease;
}

.platform-rail__items {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--platform-space-xs);
    width: 100%;
}

/* The icon-only entry: a square tap target. The label is the accessible name (title/aria-label). */
.platform-rail__item {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    color: var(--platform-color-sidebar-text-muted);
    background: none;
    border: 0;
    border-radius: var(--platform-radius-md);
    cursor: pointer;
    text-decoration: none;
}

.platform-rail__item:hover {
    color: var(--platform-color-sidebar-text);
    background: var(--platform-color-sidebar-hover);
}

.platform-rail__item[aria-current="page"] {
    color: var(--platform-color-sidebar-text);
    background: var(--platform-color-sidebar-active);
}

.platform-rail__icon {
    width: 1.25rem;
    height: 1.25rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* A count/status chip floating on the upper-right of an icon: the static `badgeKey` chip and the M-123
   live per-user numeric badge (e.g. the open-todo count) share this appearance, token-driven throughout. */
.platform-rail__badge {
    position: absolute;
    top: 0.125rem;
    right: 0.125rem;
    min-width: 1rem;
    padding: 0 0.25rem;
    font-size: var(--platform-font-size-xs);
    line-height: 1rem;
    text-align: center;
    color: var(--platform-color-on-accent);
    background: var(--platform-color-error);
    border-radius: 1rem;
}

/* User initial + sign-out pinned to the foot of the rail. */
.platform-rail__foot {
    margin-top: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--platform-space-xs);
}

/* User menu (M-096): the rail-foot avatar is now a MENU trigger. The wrapper anchors the flyout popover
 * (shared appearance in `.platform-popover`) and the DevTools-gated dev modal; the avatar circle is the
 * `.platform-rail__avatar` trigger button inside it. */
.platform-rail__user {
    position: relative;
    display: inline-flex;
}

.platform-rail__avatar {
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: var(--platform-color-sidebar-text);
    color: var(--platform-color-accent);
    font-size: var(--platform-font-size-sm);
    font-weight: 700;
}

/* The avatar keeps its accent-on-light circle on hover (not the rail's square hover fill), so it still
 * reads as the user chip while remaining a button. */
.platform-rail__avatar:hover {
    background: var(--platform-color-sidebar-text);
    color: var(--platform-color-accent);
}

/* Persistent "developer slow-network simulation is on" marker (M-097): a small warning dot on the avatar so a
 * developer never forgets a self-imposed delay is slowing their session. Only rendered for a developer with
 * the simulator active; theme-token coloured so it re-skins. */
.platform-rail__dev-flag {
    position: absolute;
    top: -0.15rem;
    right: -0.15rem;
    width: 0.65rem;
    height: 0.65rem;
    background: var(--platform-color-error);
    border: 2px solid var(--platform-color-sidebar);
    border-radius: 50%;
}

/* Anchor the user menu to the right of the avatar, its foot aligned to the trigger (like the language and
 * theme popovers). */
.platform-user-menu {
    left: calc(100% + var(--platform-space-sm));
    bottom: 0;
}

/* Theme sun/moon cycle button (M-094) — a rail button that flips the active theme between the user's two
 * starred favourites (A↔B). Its glyph depicts the TARGET favourite's Bootstrap base: a SUN when a tap
 * switches TO a light-base theme, a MOON when it switches TO a dark-base one, so it reads correctly
 * whatever the two favourites are. Both glyphs are in the markup; the controller keeps `data-target-base`
 * pointed at the target's base and CSS reveals the matching one (no JS touches markup, §4). */
.platform-theme-toggle__icon {
    display: none;
}

.platform-theme-toggle[data-target-base="light"] .platform-theme-toggle__icon--sun,
.platform-theme-toggle[data-target-base="dark"] .platform-theme-toggle__icon--moon {
    display: block;
}

/* Language switcher (M-083) — a rail flag button that opens a small locale menu to its right. The
 * trigger reuses the rail's icon-button box; the flag sits centered inside it. */
.platform-lang {
    position: relative;
    display: inline-flex;
}

.platform-lang__flag {
    display: block;
    width: auto;
    height: 1rem;
    border-radius: 2px;
    box-shadow: inset 0 0 0 1px var(--platform-color-border);
}

/* Anchor the language menu to the right of its trigger. The shared popover appearance is in
 * `.platform-popover` below; only the anchoring is switcher-specific. */
.platform-lang .platform-popover {
    left: calc(100% + var(--platform-space-sm));
    bottom: 0;
}

/* ── Rail popover (M-083 language switcher + M-086 style picker) ──────────────────────────────────
 * The shared flyout menu appearance behind both rail popovers (the JS twin is popover_controller.js):
 * a dropdown on the app surface (not the dark rail), positioned absolutely by each host's own rule
 * above, and hidden via the `hidden` attribute until its controller opens it. The rail is
 * `overflow: visible`, so the menu escapes the narrow column. */
.platform-popover {
    position: absolute;
    z-index: 60;
    min-width: 9rem;
    margin: 0;
    padding: var(--platform-space-xs);
    list-style: none;
    background: var(--platform-color-surface);
    border: 1px solid var(--platform-color-border);
    border-radius: var(--platform-radius-md);
    box-shadow: var(--platform-shadow-md);
}

.platform-popover[hidden] {
    display: none;
}

.platform-popover form {
    margin: 0;
}

.platform-popover__option {
    display: flex;
    align-items: center;
    gap: var(--platform-space-sm);
    width: 100%;
    padding: var(--platform-space-xs) var(--platform-space-sm);
    color: var(--platform-color-text);
    font-size: var(--platform-font-size-sm);
    text-align: left;
    text-decoration: none;
    background: none;
    border: 0;
    border-radius: var(--platform-radius-sm);
    cursor: pointer;
}

/* The small glyphs on user-menu rows (M-096) sit inline with the label; they inherit the option's colour
 * via currentColor so they re-skin with the theme. */
.platform-user-menu .platform-rail__icon {
    flex-shrink: 0;
    width: 1.1rem;
    height: 1.1rem;
}

.platform-popover__option:hover,
.platform-popover__option:focus-visible {
    background: var(--platform-color-surface-muted);
}

/* The active option reads as selected: accent-tinted, its label emphasized. */
.platform-popover__option[aria-checked="true"] {
    color: var(--platform-color-accent);
    background: var(--platform-color-accent-surface);
    font-weight: 600;
}

.platform-popover__label {
    white-space: nowrap;
}

/* ── Style picker (M-086 + M-089 + M-094) — the theme control wrapper: the sun/moon cycle button with a
 * PALETTE selector button stacked beneath it that opens the shared popover listing every configured
 * theme. The two buttons stack vertically so the rail column stays icon-narrow (M-094 replaced M-089's
 * floating "+"). */
.platform-style {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--platform-space-xs);
}

/* The palette selector reads as active while its menu is open (M-094), matching the rail's active-item
 * treatment so the open state is obvious. */
.platform-theme-styles[aria-expanded="true"] {
    color: var(--platform-color-sidebar-text);
    background: var(--platform-color-sidebar-active);
}

/* Anchor the theme menu to the right of the button stack (like the language switcher), with its foot
 * aligned to the selector button that opens it. */
.platform-style .platform-popover {
    left: calc(100% + var(--platform-space-sm));
    bottom: 0;
}

/* The colour chip previewing each theme; its per-theme `background` is set by the nonce'd <style> the
 * style-picker partial emits from the config swatch (data, not a static rule). */
.platform-style__swatch {
    flex-shrink: 0;
    width: 1rem;
    height: 1rem;
    border-radius: 2px;
    box-shadow: inset 0 0 0 1px var(--platform-color-border);
}

/* A popover row (M-089): the theme-select button (grows) + the ★ favourite toggle (fixed) side by
 * side, so a theme can be both applied and starred from the same line. */
.platform-style__row {
    display: flex;
    align-items: center;
    gap: var(--platform-space-xs);
}

.platform-style__row .platform-popover__option {
    flex: 1 1 auto;
}

/* The background-image toggle (M-197) is the shared .platform-checkbox dropped into the popover, so — like
 * .platform-popover__option above — it must reclaim the popover's on-surface text colour: the rail sets
 * `color: var(--platform-color-sidebar-text)` which otherwise inherits down and paints the label the same
 * colour as the light popover surface (invisible). Scoped to THIS row so the shared checkbox is untouched
 * for its other callers; the label span has no own colour, so this cascades into it. */
.platform-style__row--background .platform-style__background-toggle {
    color: var(--platform-color-text);
}

/* ★ favourite toggle: a hollow star when off, filled with the accent when the theme is one of the two
 * favourites (aria-pressed="true"). Pure CSS state swap off the ARIA state (no JS touches markup, §4). */
.platform-style__star {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    color: var(--platform-color-text-muted);
    background: none;
    border: 0;
    border-radius: var(--platform-radius-sm);
    cursor: pointer;
}

.platform-style__star:hover,
.platform-style__star:focus-visible {
    background: var(--platform-color-surface-muted);
}

.platform-style__star[aria-pressed="true"] {
    color: var(--platform-color-accent);
}

.platform-style__star-icon {
    width: 1rem;
    height: 1rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
    stroke-linejoin: round;
}

.platform-style__star[aria-pressed="true"] .platform-style__star-icon {
    fill: currentColor;
}

/* Instant label chip — keeps the rail icon-only but discoverable, replacing the slow native `title`
 * tooltip (M-036 BFU follow-up). Appears to the right of the rail on hover and keyboard focus; the
 * link's `aria-label` remains the accessible name, so this span is decorative (`aria-hidden`). */
.platform-rail__tooltip {
    position: absolute;
    left: calc(100% + var(--platform-space-sm));
    top: 50%;
    transform: translateY(-50%);
    z-index: 60;
    padding: var(--platform-space-xs) var(--platform-space-sm);
    white-space: nowrap;
    font-size: var(--platform-font-size-sm);
    font-weight: 500;
    color: var(--platform-color-surface);
    background: var(--platform-color-text);
    border-radius: var(--platform-radius-sm);
    box-shadow: var(--platform-shadow-md);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.12s ease;
}

.platform-rail__item:hover .platform-rail__tooltip,
.platform-rail__item:focus-visible .platform-rail__tooltip {
    opacity: 1;
    visibility: visible;
}

/* ── Secondary (tier-2) panel — module-owned, present only when the active module supplies it. ── */
/* Fixed beside the rail (its left edge starts at the rail width), pinned below the top bar. Its hidden
 * transform pulls it fully off the left — past its own width PLUS the rail width — so nothing pokes back
 * over the rail's column (the old sliver bug). Revealed by the media-scoped nav rules below. */
.platform-subnav {
    position: fixed;
    top: var(--platform-topbar-height);
    bottom: 0;
    left: var(--platform-rail-width);
    z-index: 49;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    width: var(--platform-subnav-width);
    padding: var(--platform-space-md) var(--platform-space-sm);
    overflow-y: auto;
    background: var(--platform-color-subnav-surface);
    border-right: 1px solid var(--platform-color-subnav-border);
    transform: translateX(calc(-100% - var(--platform-rail-width)));
    transition: transform 0.2s ease;
}

.platform-subnav__heading {
    margin: 0 0 var(--platform-space-sm);
    padding: 0 var(--platform-space-sm);
    font-size: var(--platform-font-size-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--platform-color-text-muted);
}

.platform-subnav__list {
    margin: 0;
    padding: 0;
    list-style: none;
    /* Keep natural height inside the flex column so a long menu scrolls the rail rather than squashing
       entries; the admin band below claims any leftover space to bottom-pin itself. */
    flex-shrink: 0;
}

/* The module's admin/config band (M-192): pinned to the FOOT of the rail. `margin-top:auto` eats the free
   space above it in the flex column, dropping it beside the shell's account controls; a top border/spacing
   sets it apart from the content entries. When the menu overflows, the auto margin collapses to zero and
   the band simply flows after the content, still reachable by scrolling (mobile/short-viewport degrade). */
.platform-subnav__list--admin {
    margin-top: auto;
    padding-top: var(--platform-space-sm);
    border-top: 1px solid var(--platform-color-subnav-border);
    /* Match the content list: never let the pinned band compress under overflow (explicit intent). */
    flex-shrink: 0;
}

.platform-subnav__link {
    display: flex;
    align-items: center;
    gap: var(--platform-space-sm);
    padding: var(--platform-space-sm);
    color: var(--platform-color-text);
    text-decoration: none;
    border-radius: var(--platform-radius-md);
    font-size: var(--platform-font-size-sm);
}

.platform-subnav__link:hover {
    background: var(--platform-color-subnav-hover);
}

.platform-subnav__link[aria-current="page"] {
    color: var(--platform-color-accent);
    background: var(--platform-color-subnav-active);
    font-weight: 600;
}

/* A leading glyph for opt-in entries (the pinned "New …" create action). Sized to the label and drawn in
   the accent colour via currentColor, so it reads as an "add new" affordance and re-skins per theme —
   in both light and dark mode — from --platform-color-accent. Icon-less entries render no such span. */
.platform-subnav__icon {
    display: inline-flex;
    flex-shrink: 0;
    color: var(--platform-color-accent);
}

.platform-subnav__icon .platform-rail__icon {
    width: 1.15em;
    height: 1.15em;
}

/* Badge sits at the trailing edge regardless of a leading icon (replaces the former space-between). */
.platform-subnav__badge {
    min-width: 1.25rem;
    margin-left: auto;
    padding: 0 0.375rem;
    font-size: var(--platform-font-size-xs);
    line-height: 1.25rem;
    text-align: center;
    color: var(--platform-color-on-accent);
    background: var(--platform-color-error);
    border-radius: 1rem;
}

/* ── Collapsible secondary-navigation groups (M-306) ──────────────────────────────────────────────
 * A group is a header button over its own entry list. The `nav-group` controller flips `data-collapsed`
 * on the group root; everything here is token-driven so it re-skins with the subnav tokens (light/dark
 * and every named theme), and nothing here is inline (coding-standards §4). Present only when a module
 * assigns entries to a group — an ungrouped menu never emits this markup, so its look is unchanged. */
.platform-subnav__group {
    /* Match the two lists it sits between: never compress under overflow — the menu scrolls instead. */
    flex-shrink: 0;
}

.platform-subnav__group + .platform-subnav__group {
    margin-top: var(--platform-space-xs);
}

/* The header reads like the panel heading (small, muted, uppercase) but is a full-width button: the whole
   row is the hit target, the chevron sits at the trailing edge. Reset the native button chrome so it is a
   header, not a form control. */
.platform-subnav__group-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--platform-space-sm);
    width: 100%;
    margin: 0;
    padding: var(--platform-space-sm);
    background: none;
    border: 0;
    border-radius: var(--platform-radius-md);
    color: var(--platform-color-text-muted);
    font: inherit;
    font-size: var(--platform-font-size-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    text-align: start;
    cursor: pointer;
}

.platform-subnav__group-toggle:hover {
    background: var(--platform-color-subnav-hover);
}

.platform-subnav__group-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The disclosure caret: points down when open, flips up when the group is collapsed. */
.platform-subnav__group-chevron {
    display: inline-flex;
    flex-shrink: 0;
    transition: transform 0.15s ease;
}

.platform-subnav__group-chevron .platform-rail__icon {
    width: 1em;
    height: 1em;
}

/* Collapsed: hide the entry list and rotate the caret. Keyed off the flag the controller writes, so the
   pre-JS default (data-collapsed="false" in the partial) renders open and accessible. */
.platform-subnav__group[data-collapsed="true"] .platform-subnav__group-list {
    display: none;
}

.platform-subnav__group[data-collapsed="true"] .platform-subnav__group-chevron {
    transform: rotate(180deg);
}

/* Mobile drawer backdrop — covers the content below the top bar while the drawer is open (revealed by
 * the mobile media rule keyed on the nav-open flag). Sits below the top bar so its toggle stays live. */
.platform-shell__scrim {
    display: none;
    position: fixed;
    inset: var(--platform-topbar-height) 0 0 0;
    z-index: 45;
    background: var(--platform-color-scrim);
}

/* ── Content frame ────────────────────────────────────────────────────────────────────────── */
.platform-shell__main {
    flex: 1;
    width: 100%;
    max-width: var(--platform-content-max-width);
    margin: 0 auto;
    padding: var(--platform-space-lg) var(--platform-space-md);
    box-sizing: border-box;
    /* Own stacking context (M-244). The background photo lives on the fixed `::before` below at
       `z-index: -1`; without an isolated context here that negative layer would paint BEHIND the body's
       opaque page-bg and vanish. `isolation` does NOT create a containing block for the fixed pseudo, so
       it stays pinned to the viewport. The chrome (rail/subnav/top-bar) is a SIBLING of this column with
       its own higher z-index, and content never needs to paint over it, so scoping this subtree's z-order
       is safe. */
    isolation: isolate;
}

/* Theme background photo (M-197, M-244). ONE viewport-pinned layer carries the veil + photo — a
   `position: fixed` pseudo-element rather than the old `background-attachment: fixed` on this column
   (M-244 fix 4): same "pinned to the viewport, does not scroll under a long table" look, but a cheap
   composited layer instead of the repaint-on-scroll, non-GPU path. The photo URL is DATA (config), set
   per-theme as `--platform-content-bg-image` by the values-only <style> in the theme-background partial
   — already composited under the veil (`--platform-content-bg-overlay`). `--platform-content-bg-color`
   is the per-theme placeholder tone (wired from `--platform-content-bg-tone` in the SAME image-gated
   rule) painted UNDER the photo, so the sliver of time before the (preloaded) picture decodes settles on
   the photo's dominant tone instead of flashing the bare body colour (M-244 fix 3). An image-less theme
   sets NEITHER custom property → both fall back (transparent / none) → the layer is invisible and that
   theme's look is untouched. */
.platform-shell__main::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-color: var(--platform-content-bg-color, transparent);
    background-image: var(--platform-content-bg-image, none);
    background-repeat: no-repeat;
    background-position: center center;
    background-size: cover;
}

/* The style-picker toggle (M-197): turning the background OFF flags <html>; ONLY the photo layer is
   suppressed — the theme colours (data-theme / data-bs-theme) are untouched. Absent flag ⇒ ON (default).
   Hiding the whole `::before` drops both the photo and its placeholder tone in one move. */
:root[data-theme-background="off"] .platform-shell__main::before {
    display: none;
}

/* ── Embedded mode: content fills the iframe, no chrome, no centring cap. ─────────────────── */
.platform-shell--embedded {
    min-height: auto;
    background: var(--platform-color-surface);
}

.platform-shell--embedded .platform-shell__main {
    max-width: none;
    padding: var(--platform-space-md);
}

/* ── Mobile (< 48rem): rail + subnav are an off-canvas drawer over a scrim. ──────────────────── */
/* The nav is hidden by the base transforms; the drawer flag on <html> slides both in together and
 * reveals the scrim. Content is NOT offset — the drawer overlays it. */
@media (max-width: 47.99rem) {
    :root[data-nav-open="true"] .platform-rail {
        transform: translateX(0);
        box-shadow: var(--platform-shadow-md);
    }

    :root[data-nav-open="true"] .platform-subnav {
        transform: translateX(0);
    }

    :root[data-nav-open="true"] .platform-shell__scrim {
        display: block;
    }
}

/* ── Tablet and up (≥ 48rem): rail + subnav are fixed columns; content is offset by their width. ──
 * Default is EXPANDED (nav on-screen, content pushed right). The collapse flag on <html> slides both
 * off-screen and drops the content offset to zero so it reflows to full width. No scrim here. */
@media (min-width: 48rem) {
    .platform-rail {
        transform: translateX(0);
        box-shadow: none;
    }

    .platform-subnav {
        transform: translateX(0);
    }

    /* Content clears the fixed rail; a present subnav (general sibling) adds its width too. */
    .platform-shell__content-col {
        margin-left: var(--platform-rail-width);
        transition: margin-left 0.2s ease;
    }

    .platform-subnav ~ .platform-shell__content-col {
        margin-left: calc(var(--platform-rail-width) + var(--platform-subnav-width));
    }

    /* Collapsed: slide the nav off-screen (same hidden transforms as the mobile base) and reclaim the
     * offset. Higher specificity than the offset rules above, so it wins for both the with- and
     * without-subnav cases. */
    :root[data-nav-collapsed="true"] .platform-rail {
        transform: translateX(-100%);
    }

    :root[data-nav-collapsed="true"] .platform-subnav {
        transform: translateX(calc(-100% - var(--platform-rail-width)));
    }

    :root[data-nav-collapsed="true"] .platform-shell__content-col {
        margin-left: 0;
    }

    .platform-shell__main {
        padding: var(--platform-space-xl) var(--platform-space-xl);
    }
}

/* ── Developer-tools modal (M-096) ────────────────────────────────────────────────────────────────
 * A native <dialog> opened from the rail user menu, DevTools-gated (never in the DOM for a non-developer).
 * Token-styled so it re-skins with the theme; a SHELL that M-097/M-098 fill via `@push('dev-tools')`. The
 * native top-layer + ::backdrop give the modal overlay for free. */
.platform-dev-tools {
    width: min(40rem, calc(100vw - 2 * var(--platform-space-lg)));
    max-height: calc(100vh - 2 * var(--platform-space-lg));
    padding: 0;
    color: var(--platform-color-text);
    background: var(--platform-color-surface);
    border: 1px solid var(--platform-color-border);
    border-radius: var(--platform-radius-lg);
    box-shadow: var(--platform-shadow-lg, var(--platform-shadow-md));
    overflow: hidden;
}

.platform-dev-tools::backdrop {
    background: rgba(0, 0, 0, 0.45);
}

.platform-dev-tools__panel {
    display: flex;
    flex-direction: column;
    max-height: inherit;
}

.platform-dev-tools__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--platform-space-md);
    padding: var(--platform-space-md) var(--platform-space-lg);
    border-bottom: 1px solid var(--platform-color-border);
}

.platform-dev-tools__title {
    margin: 0;
    font-size: var(--platform-font-size-lg);
    font-weight: 600;
}

.platform-dev-tools__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    color: var(--platform-color-text-muted, var(--platform-color-text));
    background: none;
    border: 0;
    border-radius: var(--platform-radius-md);
    cursor: pointer;
}

.platform-dev-tools__close:hover,
.platform-dev-tools__close:focus-visible {
    background: var(--platform-color-surface-muted);
}

.platform-dev-tools__close-icon {
    width: 1.25rem;
    height: 1.25rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.platform-dev-tools__body {
    padding: var(--platform-space-lg);
    overflow-y: auto;
}

.platform-dev-tools__placeholder {
    margin: 0;
    color: var(--platform-color-text-muted, var(--platform-color-text));
    font-size: var(--platform-font-size-sm);
}

/* Each tool M-097/M-098 pushes is a titled section; spacing between them lives here so the tools carry no
 * layout of their own. */
.platform-dev-tools__section + .platform-dev-tools__section {
    margin-top: var(--platform-space-lg);
    padding-top: var(--platform-space-lg);
    border-top: 1px solid var(--platform-color-border);
}

/* Shared chrome for a tool section's controls (M-097+). A tool pushes only its heading + control markup; the
 * layout lives here so every tool reads the same. Mobile-first: the label/select/apply stack, then sit inline
 * from the small breakpoint up (mirrors the settings form, §3). */
.platform-dev-tools__section-title {
    margin: 0 0 var(--platform-space-xs);
    font-size: var(--platform-font-size-md);
    font-weight: 600;
}

.platform-dev-tools__section-hint {
    margin: 0 0 var(--platform-space-md);
    color: var(--platform-color-text-muted, var(--platform-color-text));
    font-size: var(--platform-font-size-sm);
}

.platform-dev-tools__label {
    display: block;
    margin-bottom: var(--platform-space-xs);
    font-size: var(--platform-font-size-sm);
    font-weight: 600;
}

.platform-dev-tools__field {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--platform-space-sm);
}

.platform-dev-tools__select {
    flex: 1 1 12rem;
    max-width: 20rem;
}

/* The access-simulator feature checkboxes (M-098, M-110e): a per-module group of themeable checkboxes
 * between the tier select and the Apply button, so a developer previews a tier + a chosen feature set. */
.platform-dev-tools__features {
    margin: var(--platform-space-md) 0;
    padding: 0;
    border: 0;
}

.platform-dev-tools__feature-group + .platform-dev-tools__feature-group {
    margin-top: var(--platform-space-sm);
}

.platform-dev-tools__feature-module {
    margin: var(--platform-space-sm) 0 var(--platform-space-xs);
    color: var(--platform-color-text-muted, var(--platform-color-text));
    font-size: var(--platform-font-size-sm);
    font-weight: 600;
}

/* The access-simulator "Back to real access" control sits under its tier/feature/apply form (M-098). */
.platform-dev-tools__revert {
    margin-top: var(--platform-space-md);
}

/* Access-simulation banner (M-098): a persistent, high-contrast bar at the very top of the full shell while a
 * developer simulates access, so the artificial downgrade is impossible to miss and always one click to undo.
 * Uses the accent-strong / on-accent token PAIR — designed to be legible together in every theme incl. dark
 * (no hard-coded colours). */
.platform-dev-sim-banner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--platform-space-md);
    padding: var(--platform-space-sm) var(--platform-space-lg);
    color: var(--platform-color-on-accent);
    background: var(--platform-color-accent-strong);
    text-align: center;
}

.platform-dev-sim-banner__text {
    font-size: var(--platform-font-size-sm);
}

.platform-dev-sim-banner__role {
    font-weight: 700;
}

.platform-dev-sim-banner__features {
    opacity: 0.85;
}

.platform-dev-sim-banner__revert {
    margin: 0;
}

/* Minimal centred error body for the simulation error page (M-098): the developer hit a page their simulated
 * role can't reach; the page carries the banner above and this simple message below. Token-styled/dark-mode. */
.platform-error {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--platform-space-sm);
    min-height: 60vh;
    padding: var(--platform-space-xl) var(--platform-space-lg);
    text-align: center;
}

.platform-error__code {
    margin: 0;
    color: var(--platform-color-accent-strong);
    font-size: 3rem;
    font-weight: 700;
    line-height: 1;
}

.platform-error__title {
    margin: 0;
    font-size: var(--platform-font-size-lg);
    font-weight: 600;
}

.platform-error__hint {
    margin: 0;
    max-width: 32rem;
    color: var(--platform-color-text-muted);
    font-size: var(--platform-font-size-sm);
}

/* The revert button sits on the accent bar, so it takes the surface/accent inverse pairing to stay
 * high-contrast against it in every theme. */
.platform-dev-sim-banner__button {
    color: var(--platform-color-accent-strong);
    background: var(--platform-color-surface);
    border-color: var(--platform-color-surface);
}

.platform-dev-sim-banner__button:hover,
.platform-dev-sim-banner__button:focus-visible {
    color: var(--platform-color-accent-strong);
    background: var(--platform-color-surface-muted);
    border-color: var(--platform-color-surface-muted);
}

/* Turbo Drive navigation progress bar (M-260a). Turbo attaches the element to <html> and injects a
 * nonce'd base <style> (fixed position, 3px height, transitions) itself; we only re-point its colour
 * at the accent token so it is theme-aware — in full AND embedded mode (a host's token overrides
 * re-skin it too), the one shell rule that also applies chromeless. */
.turbo-progress-bar {
    background-color: var(--platform-color-accent, #16a085);
}
