@import url('tokens.css');

/* ============================================================================
   Home page (ADR 0031 — dnav-* prefix for the dashboard-nav list, distinct from the
   runtime's dash-* classes in dashboard.css). The page wears the shared Template B scaffold
   (the ui-md* classes in shared.css): page header, carded submenu on the well, a
   draggable splitter and a carded detail with a contextual toolbar. This file adds
   only the page-specific bits the scaffold has no slot for: the submenu internals
   (footer + list), the inline-runtime canvas host, the
   fullscreen flyout/exit and the template gallery — plus the fullscreen overrides
   that strip the scaffold frame for operator mode. Tokens only.
   ============================================================================ */

/* Positioning context for the absolutely-placed fullscreen overlays (exit + flyout). */
.dnav-page { position: relative; }

/* The Dashboard workbench owns both side rails. In view it is the ordinary three-column
   master/detail scaffold; Edit adds a resizable task rail as a fifth grid track. */
.dnav-page .dnav-workspace {
    --navigation-pane-active-width: min(var(--tree-pane-width), 34vw);
    --navigation-splitter-width: 11px;
    position: relative;
    grid-template-columns:
        var(--navigation-pane-active-width)
        var(--navigation-splitter-width)
        minmax(0, 1fr);
}

@media (max-width: 1100px) {
    .dnav-page .dnav-workspace {
        --navigation-pane-active-width: min(var(--tree-pane-width), 200px);
    }
}

@media (max-width: 720px) {
    .dnav-page .dnav-workspace {
        --navigation-pane-active-width: min(var(--tree-pane-width), 160px);
    }
}

/* The dashboards pane is this page's own column, so the mode's five tracks are restated here over
   the navigation width: everything else about the editing body — the task rail's widths, the narrow
   caps and the accent outline on the stage — is the shared scaffold's (shared.css). */
.dnav-page .dnav-workspace.editing {
    grid-template-columns:
        var(--navigation-pane-active-width)
        var(--navigation-splitter-width)
        minmax(0, 1fr)
        var(--editor-splitter-width)
        var(--editor-pane-active-width);
}

/* Collapsed the pane keeps its gutter: the rail stands off the stage by the same air as the open
   pane, so the workbench never reads as two surfaces pushed together. */
.dnav-page .dnav-workspace.navigation-collapsed {
    --navigation-pane-active-width: 44px;
}

/* ---- Submenu pane internals (inside the ui-md-tree card) -------------------- */
/* ui-md-tree provides the card (well surface, border, padding, flex column) and shared.css
   provides the collapsible column's chrome (header, collapse command, rail); the submenu only
   adds its own internal layout on top. */
.dnav-submenu { min-height: 0; }

.dnav-pane-actions {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.dnav-navigation-splitter {
    min-width: 0;
    overflow: hidden;
}

/* Collapsed there is no pane width to drag, so the gutter is spacing only: the splitter keeps its
   grid track and gives up its hairline and its grip. */
.dnav-page .dnav-workspace.navigation-collapsed .dnav-navigation-splitter { visibility: hidden; }

.dnav-navigation-scrim {
    position: absolute;
    inset: 0 0 0 44px;
    z-index: 19;
    border: 0;
    background: transparent;
    cursor: default;
}

.dnav-navigation-overlay {
    position: absolute;
    z-index: 20;
    top: 0;
    bottom: 0;
    left: 44px;
    width: min(320px, calc(100% - 44px));
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding: var(--space-3);
    border: 1px solid var(--color-stroke);
    border-left: 0;
    border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
    /* Floating, so it is a popover and takes the card tone — the pinned twin of this same pane is
       a well, but nothing sits under a panel that hovers over the stage for it to recess into. */
    background: var(--color-surface);
    box-shadow: var(--shadow-popover);
}

.dnav-submenu-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* The strip of commands under the list is the scaffold's own (ui-md-tree-footer, shared.css) —
   the same corner on every screen — so nothing about it is dressed here. */

/* The template-gallery / pin toggle (a checked button): accent wash when open. */
.dnav-page .ui-icon-btn.active {
    background: var(--color-accent);
    color: var(--color-on-accent);
}
.dnav-page .ui-icon-btn.active:hover:not(:disabled) { background: var(--color-accent-hover); }

/* ---- Submenu list (shared DashboardSubmenu) --------- */
/* The list opens straight on its first row, so the room above that row belongs to the list itself
   rather than to whatever happens to be drawn first. */
.dnav-list { display: flex; flex-direction: column; padding-top: var(--space-4); }

/* The one heading the list draws parts the unfiled unit panels from the tree above them, which is
   what its leading room is for. Opening the list it has nothing to part, and the list already
   carries that room, so it gives its own up rather than stacking a second one on top. */
.dnav-group-header {
    padding: var(--space-4) var(--space-2) var(--space-2);
    font-size: var(--font-size-eyebrow);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text-secondary);
}
.dnav-group-header:first-child { padding-top: 0; }

/* ---- Folders (optional filing; the flat list is what a station that files nothing sees) ----
   One indent step per level, applied to the row's own left padding so the accent bar stays on the
   list's edge: a filed screen reads as sitting under its folder, not as a second list. Both kinds
   of row start at the same left padding and reserve the same chevron column, so the glyphs fall on
   one column per level and a screen's step is a whole step rather than a step minus a chevron. */
.dnav-list { --dnav-indent: var(--space-4); --dnav-fold: 20px; }

/* The row is a strip holding TWO controls, because it answers two gestures: the chevron folds the
   group and the rest opens the folder on the stage. Each control washes on its own hover, which is
   what shows the operator where the boundary between them is before he presses either. */
.dnav-folder-head {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-1);
    width: 100%;
    padding: 0 var(--space-3) 0 0;
    padding-left: calc(var(--space-3) + (var(--dnav-depth, 0) * var(--dnav-indent)));
    margin: var(--space-1) 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--color-text-secondary);
}
.dnav-folder-head.renaming {
    gap: var(--space-2);
    padding-top: var(--space-2);
    padding-bottom: var(--space-2);
}

/* Open on the stage: the same lift a selected screen row takes, because a folder is a thing that
   opens exactly like a screen and the list has to say which one is showing. */
.dnav-folder-head.active { background: var(--color-surface); box-shadow: inset 0 0 0 1px var(--color-stroke); }
.dnav-folder-head.active .dnav-accent { background: var(--color-accent); }

.dnav-folder-fold,
.dnav-folder-open {
    display: flex;
    align-items: center;
    border: none;
    background: transparent;
    text-align: left;
    cursor: pointer;
    color: inherit;
    font: inherit;
}

/* The fold is a square of its own, so the chevron is a target and not a decoration on the name. */
.dnav-folder-fold {
    flex: 0 0 auto;
    justify-content: center;
    width: var(--dnav-fold);
    height: 22px;
    border-radius: var(--radius-sm);
}
.dnav-folder-fold:hover { background: var(--color-overlay-hover); }

/* A screen has no group to fold, so its row carries that square as empty space, plus the gap the
   folder row leaves after it. The reservation is the whole of the alignment: without it the
   screen's glyph lands left of the glyph of the folder holding it, and the row reads as filed
   nowhere; with it the glyph sits one indent step to the right of its folder, at every depth. */
.dnav-fold-spacer { flex: 0 0 auto; width: calc(var(--dnav-fold) + var(--space-1)); }

/* And the rest of the row is the folder itself. */
.dnav-folder-open {
    flex: 1 1 auto;
    min-width: 0;
    gap: var(--space-2);
    padding: var(--space-2);
    border-radius: var(--radius-md);
}
.dnav-folder-open:hover { background: var(--color-overlay-hover); }

/* The chevron points at the closed group and turns down as it opens — the only moving part. */
.dnav-folder-chevron {
    display: inline-flex;
    flex: 0 0 auto;
    transition: transform var(--dur-quick) var(--ease-out);
}
.dnav-folder-chevron.open { transform: rotate(90deg); }

.dnav-folder-name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--font-size-small);
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* How many screens the folder answers for, subfolders included — the reason to fold it. */
.dnav-folder-count {
    flex: 0 0 auto;
    font-size: var(--font-size-eyebrow);
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
}

/* Naming a folder is how one is created, so the field stands exactly where the header will. */
.dnav-folder-input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0 var(--space-2);
    border: 1px solid var(--color-accent);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    color: var(--color-text);
    font: inherit;
    font-size: var(--font-size-small);
}

/* RailItem idiom: rounded row, hover wash, selected = tertiary fill + accent bar. The gap is the
   folder header's, so a screen's optional mark stands off its name exactly as the folder glyph
   above it does; a row without one has nothing to space and reads unchanged. The row starts at the
   folder header's own left padding and reserves its chevron column, so a screen's glyph column is
   the glyph column a folder of the same depth would stand on. */
.dnav-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    padding: var(--space-3) var(--space-4);
    padding-left: calc(var(--space-3) + (var(--dnav-depth, 0) * var(--dnav-indent)));
    margin: var(--space-1) 0;
    border: none;
    border-radius: var(--radius-md);
    background: transparent;
    text-align: left;
    cursor: pointer;
    color: var(--color-text);
}
.dnav-item:hover { background: var(--color-overlay-hover); }
/* Selected row lifts off the well: --color-surface + a hairline inset ring, exactly like
   every sibling selected-row (.ui-tree-row.selected / .hist-run.selected / .cn-drivers-
   header.selected). The ring is what makes it read as "raised" in dark, where surface is
   darker than the well and a borderless fill would look like a hole. */
.dnav-item.active { background: var(--color-surface); box-shadow: inset 0 0 0 1px var(--color-stroke); }

.dnav-accent {
    position: absolute;
    left: 0;
    top: var(--space-2);
    bottom: var(--space-2);
    width: 3px;
    border-radius: var(--radius-pill);
    background: transparent;
}
.dnav-item.active .dnav-accent { background: var(--color-accent); }

.dnav-item-name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--font-size-small);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The quiet attention dot: this view (or a view inside this folder) holds a card whose point
   fails to read — the same fact the canvas seals that card for, surfaced where the operator picks
   a view. Consequence, not alarm: a small caution-tinted dot, no count, no motion; both themes
   ride the caution token, and the folder's dot is the same dot, so the vocabulary is learnt once. */
.dnav-attention {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: var(--radius-pill);
    background: var(--color-caution);
}

/* ---- Detail toolbar title (the open screen's or folder's name, inside .ui-md-toolbar-title).
   The room and the hairline that part it from the first verb belong to that group in shared.css,
   because every bar of this shape is spaced the same way; what is left here is how the name reads. */
.dnav-detail-title {
    min-width: 0;
    font-size: var(--font-size-body);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---- Stage bar: view mode vs edit mode ------------------------------------
   Viewing is the ordinary neutral Template-B strip. Editing is a MODE, and the
   operator must be able to tell which one is on from across the bench, without
   decoding a button — so the bar itself changes: an accent wash, an accent
   hairline where it meets the canvas, and the filled badge below. The tone is the
   brand accent, never a warning colour: assembling a screen is normal work, so the
   surface informs rather than alarms. The canvas is deliberately left untouched —
   it stays a faithful WYSIWYG surface (ADR 0030 §5). */
.dnav-stage-bar.editing {
    background: var(--color-accent-bg);
    border-bottom-color: var(--color-accent);
}

/* The mode badge: the one saturated element on the bar, so "where am I" is answered
   before a single control is read. Named after the state, beside the screen it applies to. */
.dnav-mode-badge {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
    background: var(--color-accent);
    color: var(--color-on-accent);
    font-size: var(--font-size-eyebrow);
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
}

/* The way out of the mode is a real command, not a toggle that un-presses: on the washed bar it
   takes the card surface and an accent edge, so it reads as the exit it is. It fills on hover
   (the ui-btn-accent idiom) — the neutral hover wash is translucent and would sink the button
   into the wash behind it instead of lifting it. The badge stays the only filled shape at rest. */
.dnav-stage-bar.editing .ui-toolbar-btn {
    border-color: var(--color-accent);
    background: var(--color-surface);
    color: var(--color-accent-text);
}
.dnav-stage-bar.editing .ui-toolbar-btn:hover:not(:disabled) {
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: var(--color-on-accent);
}

/* ---- Canvas host: the stage the runtime grid stands on ---------------------
   Positioning context for the absolutely-laid-out runtime grid (dash-grid); fills the
   detail below the toolbar. The runtime tiles are mostly transparent and the grid overlay
   is a translucent wash, so the host owns the canvas "paper" — and that paper is the PAGE
   backdrop (--color-bg, the depth contract's stage role), which is what makes a component's
   default surface-toned face read as a card resting on it. Windowed and full screen paint
   the same tone by construction: fullscreen adds no override, so leaving one state and
   entering the other never repaints the stage under the operator's screen. */
/* The stage with no screen open: the list can stand on a folder alone, so this is a real state and
   it takes the whole stage rather than perching at the top of it. */
.dnav-stage-empty { height: 100%; }

/* ---- The stage a folder opens onto -----------------------------------------
   A folder is a thing that opens, and what it shows is what it holds: the folders under it as rows,
   then its own screens side by side. The surface scrolls (a folder of twenty screens is read down
   the page) rather than scaling like a dashboard, which is the same parting the unit view above
   makes for the same reason. */
.dnav-folder-view {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding: var(--space-4);
}

.dnav-folder-strip {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
}
.dnav-folder-strip .field-description { max-width: 60ch; }

/* The folders inside this one, above the cards. They are rows and not pictures: a folder has no
   drawing of its own, and the two things worth knowing before pressing one are its name and how many
   screens it answers for. */
.dnav-subfolder-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

.dnav-subfolder {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    max-width: 100%;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--color-stroke);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text);
    font-size: var(--font-size-small);
    cursor: pointer;
}
.dnav-subfolder:hover { border-color: var(--color-accent); background: var(--color-overlay-hover); }
.dnav-subfolder-name {
    min-width: 0;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* The count is the second thing on the row, not part of the name: the glyph stays tight against the
   name it labels, and the number stands off on its own so a folder called "Line 3" is never read as
   "Line 3 4 screens". */
.dnav-subfolder-count {
    margin-inline-start: var(--space-3);
    color: var(--color-text-secondary);
    white-space: nowrap;
}

/* One screen filed here is one card, and it is the card the rest of the app opens a node with
   (.as-overview-card in process.css): the icon well, the name, and one line of the screen's own
   description under it. Nothing is drawn inside one, so the card is the button itself and the
   whole surface is the press. Only what a button does not inherit is added here. */
.dnav-screen-card { text-align: left; color: var(--color-text); }

/* The description is what tells two screens of similar name apart, so it is one line and is cut
   where the card ends rather than growing the card to fit a paragraph. */
.dnav-screen-what {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---- A screen drawn small (DashboardScreenThumbnail) ------------------------
   The screen itself, on its own grid and in its own proportions, laid inside a box some other
   surface gives it. The model's view arrangement is what draws one: a screen used as a card of a
   unit's view is previewed there at the height chosen for it. Nothing in it is live and nothing in
   it is reachable, so it says nothing to assistive technology and takes no pointer at all. */
.dnav-thumb-shape {
    position: relative;
    width: 100%;
    border-radius: var(--radius-md);
    background: var(--color-bg);
    box-shadow: inset 0 0 0 1px var(--color-stroke-subtle);
    overflow: hidden;
    pointer-events: none;
}
.dnav-thumb-shape * { pointer-events: none; }

/* The stage is laid out several times the drawing's size and then scaled onto it. Sizing the screen
   down in LAYOUT rather than at the end is what keeps the relations inside every component: the
   whole display contract resolves against boxes that are still screen-sized (dashboard.css), so the
   11 px readability floor never becomes the loudest thing in a small picture. The factor is fixed,
   so nothing has to be measured to draw one. */
.dnav-thumb-stage {
    --dnav-thumb-zoom: 0.25;
    position: absolute;
    top: 0;
    left: 0;
    width: calc(100% / var(--dnav-thumb-zoom));
    height: calc(100% / var(--dnav-thumb-zoom));
    transform: scale(var(--dnav-thumb-zoom));
    transform-origin: top left;
}

/* A screen nobody has put anything on yet: the drawing says the grid is empty rather than
   pretending the thumbnail failed to render. */
.dnav-thumb-bare {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    font-size: var(--font-size-description);
    color: var(--color-text-disabled);
}

/* The shape a chart takes in a thumbnail (DashboardThumbnailFigure): a silhouette in the interface's
   own accent, drawn where a chart engine would otherwise be mounted. */
.dnav-figure { width: 100%; height: 100%; }
.dnav-figure-svg { display: block; width: 100%; height: 100%; }

/* The curve keeps one weight whatever shape its cell is: the drawing stretches to the box
   (preserveAspectRatio="none"), and a stroke that stretched with it would come out thicker across
   than along. */
.dnav-figure-line {
    fill: none;
    stroke: var(--color-accent);
    stroke-width: 1.5;
    stroke-linejoin: round;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke;
}
.dnav-figure-area { fill: var(--color-accent); opacity: 0.18; stroke: none; }
.dnav-figure-bar { fill: var(--color-accent); opacity: 0.75; }
.dnav-figure-reading { fill: var(--color-text-secondary); opacity: 0.55; }

.dnav-figure-slice { fill: none; stroke-width: 50; }
.dnav-figure-slice.lead { stroke: var(--color-accent); }
.dnav-figure-slice.mid { stroke: var(--color-accent); opacity: 0.6; }
.dnav-figure-slice.rest { stroke: var(--color-stroke); }

.dnav-figure-track,
.dnav-figure-sweep,
.dnav-figure-needle {
    fill: none;
    stroke-linecap: round;
}
.dnav-figure-track { stroke: var(--color-stroke); stroke-width: 9; }
.dnav-figure-sweep { stroke: var(--color-accent); stroke-width: 9; }
.dnav-figure-needle { stroke: var(--color-text-secondary); stroke-width: 4; }

/* ---- Fullscreen overrides: strip the scaffold frame for operator mode -------
   Everything stays rendered (so the canvas + splitter never re-init); fullscreen
   just hides the page frame via CSS and lets the stage own the whole screen. */
.dnav-page.fullscreen { padding: 0; }
.dnav-page.fullscreen .ui-ph,
.dnav-page.fullscreen .ui-ph-divider,
.dnav-page.fullscreen .ui-md-tree,
.dnav-page.fullscreen .ui-md-splitter,
.dnav-page.fullscreen .ui-md-toolbar { display: none; }
.dnav-page.fullscreen .ui-md-body { grid-template-columns: 1fr; }

/* The stage draws the screen's outline and title — it is chrome AROUND the dashboard, never a
   component inside it (a full-grid frame would also swallow the grid the operator builds on).
   Windowed, the stage bar names the screen and the detail card already outlines it. Full screen
   drops both and is exactly where the operator at the bench has the least context left, so the
   stage keeps the card's hairline — inset off the monitor edge so it reads as an outline — and
   prints the name itself, in the same type as the stage bar it replaces. */
.dnav-page.fullscreen .ui-md-detail {
    margin: var(--space-3);
    border: 1px solid var(--color-stroke);
    border-radius: var(--radius-lg);
    background: transparent;
}

/* Windowed the stage bar is on duty, so the caption stays down — one title, never two. */
.dnav-stage-caption { display: none; }

/* An entry a unit's view stands for is a stack of cards, not a layout: it takes the stage the
   canvas would have taken, but it scrolls instead of scaling, because a view is read top to bottom
   and a screen inside it is the one piece that scales (to the height the view gave it). */
.dnav-unit-view {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding: var(--space-4);
}

.dnav-page.fullscreen .dnav-stage-caption {
    flex: 0 0 auto;
    display: block;
    /* The right inset clears the absolutely-placed exit button, which lands over this strip. */
    padding: var(--space-3) calc(var(--space-8) + var(--space-3)) var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-stroke);
    color: var(--color-text);
    font-size: var(--font-size-body);
    font-weight: var(--font-weight-semibold);
    line-height: 20px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---- Fullscreen exit button ----------------------------------------- */
.dnav-exit {
    position: absolute;
    top: var(--space-4);
    right: var(--space-4);
    z-index: 30;
    opacity: 0.55;
    transition: opacity var(--dur-quick) var(--ease-out);
}
.dnav-exit:hover { opacity: 1; }

/* ---- Fullscreen auto-hide flyout -------------------------------
   The host is a NARROW left strip (only the hot edge + handle are a persistent hit
   area, so the rest of the fullscreen canvas stays clickable). The panel is absolutely
   positioned (no layout footprint when hidden) but a DOM descendant, so hovering the
   shown panel keeps host:hover true. Revealed on host hover OR when pinned. */
.dnav-flyout-host {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 18px;
    z-index: 25;
}

/* Hot edge: hovering the left border reveals the flyout. */
.dnav-flyout-edge {
    width: 18px;
    height: 100%;
}

/* Edge handle: a visible, clickable affordance (click pins the menu). */
.dnav-flyout-handle {
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 64px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    background: var(--color-surface-alt);
    color: var(--color-text-secondary);
    cursor: pointer;
}

/* The flyout panel: hidden by default; shown on host hover OR when pinned. */
.dnav-flyout-panel {
    position: absolute;
    left: 0;
    top: var(--space-3);
    width: 248px;
    display: flex;
    flex-direction: column;
    /* Size against the fullscreen canvas, not the viewport: when the selected Dashboard keeps
       the status bar, the shell has already reserved that band below this containing block. */
    max-height: calc(100% - var(--space-6));
    border: 1px solid var(--color-stroke);
    border-left: none;
    border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
    background: var(--color-surface);
    box-shadow: var(--shadow-popover);
    opacity: 0;
    visibility: hidden;
    transform: translateX(-8px);
    transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out), visibility var(--dur-base);
}
.dnav-flyout-host:hover .dnav-flyout-panel,
.dnav-flyout-host.pinned .dnav-flyout-panel {
    opacity: 1;
    visibility: visible;
    transform: translateX(0);
}

.dnav-flyout-header {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-3) var(--space-3) var(--space-2) var(--space-5);
}
.dnav-flyout-title {
    font-size: var(--font-size-small);
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
}
.dnav-flyout-actions { display: flex; align-items: center; gap: var(--space-2); }
.dnav-flyout-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 0 var(--space-3) var(--space-3);
}

