/* AUTO-SYNCED COPY — DO NOT EDIT. Canonical: Antares shared/ui/. Run `npm run sync-shared` there. */
/* bento.css — CANONICAL SOURCE of the "Bento" panel look: every section on a page
   contained in a visually identical box, with a small title sitting ON the panel's own
   top border (like a fieldset legend), a collapse toggle, and a maximize toggle.
   This repo (C:\Dev\Bento) is its home — panel work and its cross-engine verification
   (test-visual.mjs) happen HERE. Antares vendors this file to shared/ui/panels.css via
   `npm run sync-shared`, which fans it out to dash/panels.css and ServerManage. Do NOT
   edit the vendored copies — edit here. `.stage .bento-panel` rules near the end are
   physics-demo-only and inert anywhere without a `.stage` container.

   Both apps already have their OWN panel styling (Antares: .glass-panel/.collapsible-panel
   in dash/style.css; ServerManage: .panel in public/css/index.css) — this file does not
   replace either. It adds a new, additive `.bento-panel` class + a small set of pieces
   (`.bento-panel-header`, `.bento-panel-title`, `.bento-panel-actions`,
   `.bento-panel-btn`, `.bento-panel-content`) that a page opts a section into, so the
   migration can happen panel by panel instead of as one repo-wide rewrite. Reads each
   host's own theme tokens with a generic fallback chain (--panel-bg / --card-bg / a
   literal color) so it renders sanely in either app without either app renaming its
   existing variables.

   Markup does NOT pair `.bento-panel-header`/`.bento-panel-title` with the older
   `.section-header`/`h2` selectors from dash/style.css — that class carries its own
   `.section-header h2 { font-size:18px; font-weight:600 }` rule, which (being two
   selector components against this file's one) wins the cascade on specificity no
   matter what size is set here. Real bug, caught 2026-08-22: every migrated Vision
   panel's title rendered at 18px instead of the intended ~13px. `.bento-panel-header`
   is a complete replacement for `.section-header`, not a layer on top of it.

   Collapse re-uses the SAME JS engine as the older .collapsible-panel class
   (shared/ui/panels.js#autoWireCollapsible) — `.bento-panel` is meant to be paired with
   `.collapsible-panel` in markup, not to replace it. Maximize is new: see
   autoWireCollapsible's maximize-button wiring in shared/ui/panels.js. */

.bento-panel {
    background: var(--panel-bg, var(--card-bg, rgba(26, 29, 41, 0.6)));
    border: 1px solid var(--panel-border, rgba(var(--tint, 255, 255, 255), 0.1));
    border-radius: var(--panel-radius, 16px);
    box-shadow: var(--panel-shadow, none);
    backdrop-filter: blur(var(--panel-blur, 0px));
    padding: 16px 18px 16px;
    margin-bottom: 16px;
    position: relative;
    /* Header straddles the top border (translateY -50%). If an author sets
       overflow:hidden inline for media rounding (e.g. a product card), the
       header would be clipped. Keep the panel itself visible; inner content
       handles its own clipping. */
    overflow: visible;
}
.bento-panel:has(> .bento-panel-header) {
    overflow: visible !important;
    /* Reserve header clearance even when an author sets padding:0 for media rounding
       (e.g. splash.html product card). Without this the 12px header half inside the
       panel overlaps the content's top-left corner and the header's pill covers it. */
    padding-top: 18px !important;
}
.bento-panel:has(> .bento-panel-header) > .bento-panel-content {
    overflow: hidden;
    /* Do NOT set border-radius here. This div is already inside the panel's own
       padding (16px top / 18px sides), so its corners are nowhere near the panel's
       visible rounded edges. border-radius:inherit was clipping the content box's
       OWN inner corners, cutting off text/glyphs at all four edges — especially
       visible on sand/glass (20px radius) and any time a row starts near the left.
       overflow:hidden on a rectangular box is all the collapse animation needs. */
    position: relative;
    z-index: 0;
    /* Minimum safe inset from a corner clip with radius R: R × (1 − cos 45°) ≈ R × 0.293.
       For 20px (sand/glass) → ~5.9px, for 16px (default) → ~4.7px.
       4px horizontal + 2px vertical covers both theme ranges with a small margin. */
    padding: 2px 4px;
    box-sizing: border-box;
}

/* The legend: a small pill straddling the panel's own top border, title on the left,
   collapse/maximize (and any per-panel buttons/filters) on the right — "the actual top
   panel borderline" rather than a separate header bar eating vertical space above the
   content. `pointer-events:none` on the row + `auto` on the two pills is what lets the
   row span the full width (so the right-hand pill can sit flush right) without
   intercepting clicks in the gap between the two pills. */
.bento-panel-header {
    position: absolute;
    top: 0;
    left: 14px;
    right: 14px;
    transform: translateY(-50%);
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    /* nowrap, not wrap: wrapping is what "detaches" the buttons — the header is
       position:absolute and pokes above the panel's top edge, so a wrapped second row
       floats free above the panel with nothing behind it. The title already truncates
       (min-width:0 + ellipsis below); let it eat the shrink and keep the row intact. */
    flex-wrap: nowrap;
    gap: 8px;
    /* Header is the drag handle (so content stays selectable/copyable). The row
       itself is interactive so the whole header bar — including the gap between
       title and actions — is grabbable; the two pills keep pointer-events:auto
       so their buttons still fire. */
    pointer-events: auto;
    z-index: 2;
    cursor: default;
}

/* Title pill needs a SOLID background to cover the border it straddles — otherwise the
   panel's own top border line reads straight through the text. Tuned to the PANEL
   surface, not the bare page colour: --panel-bg is usually translucent, so a pill in raw
   --bg-color looks like a hole punched in the panel's top edge. Layering --panel-bg over
   --bg-color reproduces the exact blend the panel body shows, so the pill melts into the
   border it hides. background-image (not a second background-color) is how you stack the
   two in one declaration.
   Actions pill gets the SAME solid treatment: it straddles the same top border, and
   with a faint rgba border the line showing through the gaps was invisible — but with
   a solid/opaque --panel-border the line cuts straight through the translucent icon
   buttons and the gaps between them, making the icons unreadable. An opaque pill
   breaks the border behind the controls, exactly like the title does. */
.bento-panel-title,
.bento-panel-summary {
    pointer-events: auto;
    background-color: var(--panel-title-bg, var(--bg-color, #14161f));
    background-image: linear-gradient(var(--panel-bg, transparent), var(--panel-bg, transparent));
    border-radius: 6px;
}
.bento-panel-actions {
    pointer-events: auto;
    background-color: var(--panel-title-bg, var(--bg-color, #14161f));
    background-image: linear-gradient(var(--panel-bg, transparent), var(--panel-bg, transparent));
    border-radius: 6px;
    /* opaque — breaks the border behind the icons, same as the title pill */
    display: flex;
    align-items: center;
    gap: 4px;
    /* never compress the icon row — the title absorbs all the shrink instead */
    flex: 0 0 auto;
    margin-left: auto;
}

.bento-panel-title {
    margin: 0;
    /* THE actual "title and controls detached" bug (2026-08-24), not the width caps I kept
       chasing before: a flex item's default min-width is `auto`, meaning it refuses to
       shrink below its own unwrapped text width no matter how little room flex-shrink
       leaves it — so overflow/ellipsis never actually engaged, and a longer title
       (e.g. "Backlog / Todo") just forced the header wider than its narrow collapsed
       panel instead of truncating. min-width:0 is what makes text-overflow:ellipsis work
       inside a flex row at all. */
    min-width: 0;
    /* a hair more block padding than the summary pill: the opaque band must clear the
       panel's 1-2px top border at every theme's title font-size */
    padding: 3px 10px;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted, #94a3b8);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* One-liner "what's in here right now" (2026-08-24), shown only while collapsed — the
   title says what the panel IS, this says what's currently in it. flex:1/min-width:0 lets
   it eat whatever room the title+actions pills don't need and ellipsis the rest; never
   shown expanded, where the real content already answers the question. Populated by
   shared/ui/panels.js#autoWireCollapsible (auto, from the panel's own content) or a page's
   `panel.dataset.summary` for a curated version. */
.bento-panel-summary {
    display: none;
    flex: 1;
    min-width: 40px;
    padding: 2px 10px;
    font-size: 0.7rem;
    font-weight: 400;
    color: var(--text-muted, #94a3b8);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Was display:block on collapse — but this pill lives INSIDE the absolutely-positioned
   header, competing with the title and (up to 3) icon buttons for room in a header whose
   own width is now capped tight (2026-08-24: "title and controls are detached" — the
   header's real content needed more width than the collapsed panel had, so it wrapped/
   overflowed instead of sitting cleanly on the border). The roomier .bento-panel-collapsed-
   body line already shows the same text below the panel, so the header copy is now just
   dead weight — stays hidden. */

.bento-panel-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    padding: 2px;
    /* A header with a long filter row (search box + several selects, e.g. Vision's
       Agents panel) still fits under the legend model, it just wraps onto its own
       line inside the pill rather than forcing the whole row wider than the panel. */
    max-width: 100%;
}

.bento-panel-btn {
    background: rgba(var(--tint, 255, 255, 255), 0.12);
    border: 1px solid rgba(var(--tint, 255, 255, 255), 0.08);
    color: var(--text-muted, #94a3b8);
    width: 22px;
    height: 22px;
    border-radius: 5px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 0.68rem;
    flex-shrink: 0;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

/* Collapse button is the primary interaction — make it visually weightier */
.bento-panel-btn.bento-collapse-btn {
    width: 28px;
    height: 28px;
    border-radius: 6px;
    font-size: 0.85rem;
    background: rgba(var(--tint, 255, 255, 255), 0.05);
    border-color: transparent;
    transition: background 0.15s ease, color 0.15s ease, transform 0.2s ease;
}

.bento-panel-btn:hover {
    background: rgba(var(--tint, 255, 255, 255), 0.18);
    border-color: rgba(var(--tint, 255, 255, 255), 0.14);
    color: var(--text-main, #e6e6e6);
}
.bento-panel-btn.bento-copy-btn.copied {
    background: rgba(22, 121, 76, 0.18);
    border-color: rgba(22, 121, 76, 0.35);
    color: var(--ok, #16794c);
}

/* ── Copy affordances ─────────────────────────────────────────────────── */
/* Per-row copy: a tiny icon button that appears on hover/focus. Works for
   .rows li and any [data-copy-row] element. Entirely opt-in via JS
   (enableRowCopy) so non-list panels pay nothing. */
.bento-row-copy {
    opacity: 0;
    width: 20px;
    height: 20px;
    border-radius: 4px;
    border: 1px solid transparent;
    background: transparent;
    color: var(--text-muted, #94a3b8);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 0.68rem;
    line-height: 1;
    flex-shrink: 0;
    transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.rows li:hover .bento-row-copy,
.rows li:focus-within .bento-row-copy,
.bento-row-copy:focus-visible,
.bento-row-copy.copied {
    opacity: 1;
}
.bento-row-copy:hover {
    background: rgba(var(--tint, 255, 255, 255), 0.12);
    border-color: rgba(var(--tint, 255, 255, 255), 0.08);
    color: var(--text-main, #e6e6e6);
}
.bento-row-copy.copied {
    color: var(--ok, #16794c);
    border-color: rgba(22, 121, 76, 0.25);
    background: rgba(22, 121, 76, 0.12);
}
/* Double-click hint: rows that are copyable show a subtle affordance */
.bento-copy-row {
    position: relative;
}

/* Toast shown after copy (panel or row) */
.bento-copy-toast {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%) translateY(8px);
    background: var(--text-main, #16130f);
    color: var(--bg-color, #fff);
    font-size: 0.78rem;
    font-weight: 600;
    padding: 8px 14px;
    border-radius: 999px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.18);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease, transform 0.2s ease;
    z-index: 9999;
}
.bento-copy-toast.show {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

/* When drag is header-only, content is freely selectable. Panels that
   still want full-panel drag keep class bento-drag-anywhere. */
.bento-panel[draggable="true"]:not(.bento-drag-anywhere) {
    cursor: default;
}
.bento-panel[draggable="true"]:not(.bento-drag-anywhere) .bento-panel-header {
    cursor: default;
}
.bento-panel[draggable="true"]:not(.bento-drag-anywhere) .bento-panel-title,
.bento-panel[draggable="true"]:not(.bento-drag-anywhere) .bento-drag-handle {
    cursor: grab;
}
.bento-panel[draggable="true"]:not(.bento-drag-anywhere) .bento-panel-title:active,
.bento-panel[draggable="true"]:not(.bento-drag-anywhere) .bento-drag-handle:active {
    cursor: grabbing;
}

.bento-panel-content {
    margin-top: 10px;
    overflow: hidden;
    max-height: 5000px;
    transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s ease;
    opacity: 1;
    position: relative;
    z-index: 1;
}

.bento-panel.collapsed {
    /* Room for .bento-panel-collapsed-body below the straddling header — was 4px (just
       enough to close the gap), now enough for one text line too. */
    padding-bottom: 22px;
    /* Prevent horizontal scroll when collapsed — collapsed body is 340px but grid panels
       may be narrower (e.g. demo-controls 248px). Also handles the physics stage where
       a collapsed absolutely-positioned panel would otherwise overflow the stage. */
    overflow: hidden;
    max-width: 100%;
    box-sizing: border-box;
    /* Fixed heights (e.g. flow demo height:148px) must not keep a collapsed panel tall */
    height: auto !important;
    min-height: 0 !important;
}

/* Second copy of the collapsed summary (2026-08-24: "wanted something in the unused line
   in the panel itself" — the header pill is compact/cramped by design; this sits in the
   panel's own body, plainer and easier to read, using the space collapsing frees up
   instead of leaving it blank). Same text as .bento-panel-summary (panels.js#updateSummary
   writes both), just a different, roomier presentation. */
.bento-panel-collapsed-body {
    display: none;
    /* 220px (down from 400) made collapsed panels genuinely tiny, but with 4 header icons
       fighting the title+pill for the same now-narrow row, it read as cramped/disjointed
       instead of clean (2026-08-24). 260 plus the collapsed size-btn removal below gives
       the header enough room to lay out on one line without being as wide as before. */
    /* Prevent horizontal scroll: 340px would overflow a 248px demo-controls panel. Use
       100% minus padding so it never exceeds the panel's own width. */
    max-width: min(340px, calc(100% - 32px));
    padding: 0 16px;
    font-size: 0.75rem;
    color: var(--text-muted, #94a3b8);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    box-sizing: border-box;
}

.bento-panel.collapsed .bento-panel-collapsed-body {
    display: block;
}

.bento-panel.collapsed .bento-panel-content {
    max-height: 0 !important;
    opacity: 0 !important;
    pointer-events: none;
    /* Invisible via max-height/opacity, but with no width constraint of its own this
       element's natural content width (a whole table, in Team Status's case) still counted
       toward the collapsed panel's new fit-content sizing above — the panel stayed exactly
       as wide as its content wanted, defeating the fix. */
    width: 0 !important;
    overflow: hidden !important;
    /* When a panel has an explicit height (e.g. flow demo height:188px) the collapsed state
       must ignore it — otherwise the panel stays tall and the grid can't flow */
    height: 0 !important;
    min-height: 0 !important;
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
}

.bento-panel.collapsed .bento-panel-btn.bento-collapse-btn {
    transform: rotate(180deg);
}

/* Maximize: the panel lifts out of the page flow to fill the viewport (minus a small
   margin) without reparenting — position:fixed works from wherever the panel already
   sits in the DOM, unlike a createPortal-style overlay. A single shared backdrop
   element (injected once by panels.js) sits just behind it so the rest of the page
   visibly recedes and a click outside exits, same affordance shared/ui/modal.js uses.

   Deliberately SOLID here, not the panel's normal translucent/blurred surface: a small
   in-flow panel sits over a mostly-uniform page background, so a little see-through is
   fine, but a maximized panel covers arbitrary busy content behind it — real report,
   2026-08-22, the blur+translucency combo was "kind of not very readable" once
   maximized. `!important` because it must win over the host's own inline/--panel-bg
   styling, the one place this file intentionally overrides rather than layers. */
.bento-panel.maximized {
    position: fixed;
    inset: 24px;
    z-index: 9990;
    margin: 0;
    max-height: none;
    /* override any fixed height from flow demo height:188px inline */
    height: auto !important;
    min-height: 0 !important;
    width: auto !important;
    /* visible, not auto: the header pill straddles this panel's OWN top border by design
       (transform:translateY(-50%), same as every other bento panel) — overflow:auto here
       clipped that upward-poking half, cutting the resize/maximize/collapse icons off at
       the top (real report, 2026-08-24). The content pane scrolls instead, below. */
    overflow: visible;
    background: var(--bg-color, #0f111a) !important;
    backdrop-filter: none !important;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.55);
}

/* Collapse and resize don't mean anything for a panel that's already taken over the
   screen (2026-08-24) — maximize (to exit) and hide stay, since both are still real
   actions here. */
.bento-panel.maximized .bento-collapse-btn,
.bento-panel.maximized .bento-size-btn {
    display: none;
}

/* Resizing a collapsed panel's (hidden) content doesn't mean anything either, and the
   button was one of four icons competing for room in an already-narrow collapsed header
   (2026-08-24 — "disjointed messes"). Maximize/hide/collapse-to-expand stay. */
.bento-panel.collapsed .bento-size-btn {
    display: none;
}

.bento-panel.maximized .bento-panel-content {
    /* !important on both: a panel manually resized (shared/ui/panels.js#enableVerticalResize)
       leaves an inline height on this same element, which would otherwise win over a plain
       class rule and show the maximized panel at its small resized height instead of filling
       the box. */
    max-height: none !important;
    height: calc(100% - 14px) !important;
    overflow: auto;
}

.bento-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 9989;
    display: none;
}

/* The literal "bento boxes" layout: a page opts a container into this to arrange its
   `.bento-panel` children as a responsive grid of boxes instead of one stacked column —
   entirely optional, a page can keep panels stacked and still use `.bento-panel` alone.
   Supports theme customization via --bento-gap and --bento-min-col CSS variables. */
.bento-grid {
    display: grid;
    /* auto-fit, not auto-fill: collapses empty tracks to 0 so existing panels' 1fr share
       absorbs leftover width. NOT dense any more (2026-08-24): dense repacks items into
       whatever gap fits, so a newly-shown/restored panel could land anywhere in the grid
       instead of predictably after the last visible one — "palette says visible but not
       shown on screen" was this, not a real visibility bug. Opt into dense per-container
       via .bento-grid-dense if a page wants the repacking back. */
    grid-template-columns: repeat(auto-fit, minmax(var(--bento-min-col, 320px), 1fr));
    gap: var(--bento-gap, 16px);
    align-items: start;
}

.bento-grid .bento-panel {
    margin-bottom: 0;
}

/* A collapsed panel is just its header pill — it shouldn't still claim a full grid
   track's width (2026-08-24: "resizes according to its horizontal neighbours"). Every
   implicit column in this grid shares one width (repeat(auto-fit, minmax(...))), so
   without this a collapsed panel stretched to match whatever its row's tallest/widest
   sibling needed.
   EXPLICIT width, not fit-content driven by a child's own size: fit-content kept finding
   edge cases (whichever in-flow child happened to be present/absent/loaded yet decided
   the box's width, so one panel could legitimately end up sized differently from another
   depending on timing) — a flat, guaranteed number is what "still sizes according to its
   neighbours" actually needed, not a smarter derivation. */
.bento-grid .bento-panel.collapsed {
    /* 500px min (2026-08-26: Vision's Active Agents header — branch/status pill plus
       maximize/collapse icons — broke onto a second line and clipped at 400px). */
    width: max(500px, var(--bento-min-col, 320px));
    max-width: 100%;
    justify-self: start;
}

/* Per-panel size within a `.bento-grid` — the "control the size of the panels" ask
   (2026-08-23), same idea as ServerManage's dashboard `.panel.half-width` toggle
   (public/css/index.css `#dashboard-panels-container .panel.half-width`), redone for a
   CSS Grid track instead of a flex basis so it isn't locked to a single half/full split.
   Cycled by `.bento-size-btn` (wired in shared/ui/panels.js#wireSize). */
.bento-grid .bento-panel.bento-wide,
.bento-grid .bento-panel.bento-span-2 {
    grid-column: span 2;
}

.bento-grid .bento-panel.bento-span-3 {
    grid-column: span 3;
}

.bento-grid .bento-panel.bento-full,
.bento-grid .bento-panel.bento-span-full {
    grid-column: 1 / -1;
}

.bento-grid .bento-panel.bento-tall,
.bento-grid .bento-panel.bento-row-2,
.bento-grid .bento-panel.bento-row-span-2 {
    grid-row: span 2;
}

.bento-grid .bento-panel.bento-row-3,
.bento-grid .bento-panel.bento-row-span-3 {
    grid-row: span 3;
}

.bento-grid .bento-panel.bento-row-full {
    grid-row: 1 / -1;
}

.bento-grid .bento-panel.bento-hero,
.bento-grid .bento-panel.bento-featured {
    grid-column: span 2;
    grid-row: span 2;
}

/* Physics stage — freeform absolute panels still support Wider / Full / maximise.
   In a .bento-grid size is a track span; in the .stage there is no grid, so size
   maps to an explicit width that the physics body (Fling) remeasures via
   ResizeObserver. `!important` wins over the inline widths physics.html sets. */
.stage .bento-panel.bento-wide,
.stage .bento-panel.bento-span-2 {
    width: min(460px, 84vw) !important;
}
.stage .bento-panel.bento-span-3 {
    width: min(560px, 90vw) !important;
}
.stage .bento-panel.bento-full,
.stage .bento-panel.bento-span-full {
    width: min(720px, 94vw) !important;
}
/* Maximised physics panels must not be moved by the integrator's translate() */
.stage .bento-panel.maximized {
    transform: none !important;
    width: auto !important;
}

/* Masonry flow (shared/ui/panels.js#enableMasonry). The engine sets grid-auto-rows to a
   small unit and per-panel `grid-row-end: span N` from measured height, closing the
   "stairs" gap without leaving the grid. align-self:start keeps each panel at its natural
   height so the measurement can't oscillate. Fixed row-span classes are neutralised —
   height now comes from the computed span, not a track count (column spans stay). */
.bento-grid.bento-masonry > .bento-panel {
    align-self: start;
    /* the span IS the height — a panel that sets its own `height:100%` (e.g. a feed
       pane sized to fill its row in plain grid) would otherwise resolve that against
       the tiny auto-row track and collapse to a sliver with no visible background. */
    height: auto;
    min-height: 0;
}
.bento-grid.bento-masonry > .bento-panel.bento-tall,
.bento-grid.bento-masonry > .bento-panel.bento-row-2,
.bento-grid.bento-masonry > .bento-panel.bento-row-span-2,
.bento-grid.bento-masonry > .bento-panel.bento-row-3,
.bento-grid.bento-masonry > .bento-panel.bento-row-span-3,
.bento-grid.bento-masonry > .bento-panel.bento-row-full,
.bento-grid.bento-masonry > .bento-panel.bento-hero,
.bento-grid.bento-masonry > .bento-panel.bento-featured {
    grid-row: auto;
}

/* Container variants */
.bento-grid.bento-grid-dense {
    grid-auto-flow: dense;
}

.bento-grid.bento-grid-cols-2,
.bento-grid.bento-grid-2 {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 480px), 1fr));
}

.bento-grid.bento-grid-cols-3,
.bento-grid.bento-grid-3 {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
}

.bento-grid.bento-grid-cols-4,
.bento-grid.bento-grid-4 {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
}

.bento-grid.bento-grid-compact {
    gap: var(--bento-gap-compact, 10px);
    grid-template-columns: repeat(auto-fit, minmax(var(--bento-min-col-compact, 240px), 1fr));
}

/* ── Flow mode control segmented button ────────────────────────────── */
.bento-flow-seg,
.flow-mode-seg {
    display: inline-flex;
    border: 1px solid rgba(var(--tint, 255, 255, 255), 0.1);
    border-radius: 999px;
    overflow: hidden;
    background: rgba(0, 0, 0, 0.2);
}
.bento-flow-seg button,
.flow-mode-seg button {
    padding: 4px 10px;
    border: 0;
    background: transparent;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--text-muted, #94a3b8);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}
.bento-flow-seg button:hover,
.flow-mode-seg button:hover {
    color: var(--text-main, #e6e6e6);
}
.bento-flow-seg button[aria-pressed="true"],
.flow-mode-seg button[aria-pressed="true"] {
    background: var(--accent, #6366f1);
    color: var(--accent-contrast, #fff);
}

.bento-grid.bento-grid-relaxed {
    gap: var(--bento-gap-relaxed, 24px);
}

.bento-grid.bento-grid-equal {
    align-items: stretch;
}

.bento-grid.bento-grid-equal .bento-panel {
    height: 100%;
    display: flex;
    flex-direction: column;
}

.bento-grid.bento-grid-equal .bento-panel-content {
    flex: 1;
}

/* Drag-reorder feedback (shared/ui/panels.js#enableDragReorder). The dragged panel itself
   goes semi-transparent in place (native HTML5 DnD already shows a ghost under the cursor;
   this is the panel's own slot, so together they read as "picked up, here's where it was").
   Every sibling dims slightly so the grid reads as "reorder in progress", and the panel
   currently under the cursor gets a colored outline naming exactly where a drop lands —
   the "semi transparent... snap it to the grid" ask (2026-08-24). Transform/opacity/outline
   only: no layout property animates, so this stays cheap even while dragover fires rapidly. */
.bento-panel.bento-dragging {
    opacity: 0.35;
}

.bento-grid.bento-drag-active .bento-panel:not(.bento-dragging) {
    opacity: 0.7;
    transition: opacity 0.15s ease, outline-color 0.15s ease;
}

.bento-panel.bento-drop-target {
    opacity: 1 !important;
    outline: 2px dashed var(--accent-blue, #3b82f6);
    outline-offset: -2px;
    background: color-mix(in srgb, var(--accent-blue, #3b82f6) 8%, var(--panel-bg, var(--card-bg, rgba(26, 29, 41, 0.6))));
}

/* Panel palette (2026-08-24): "add and take away panels for that tab" — a popover listing
   every panel a page's bento grid can show, driven by createPanelManager#drawerHTML. Panel
   markup owns the trigger button; this just anchors the dropdown under it. */
.dashboard-panels-popover {
    display: none;
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 40;
    /* Bigger (2026-08-24) — the catalog grew to 25 entries and 320px tall showed barely
       five of them. Wide enough for the two-column row grid below. */
    min-width: 620px;
    max-height: 520px;
    overflow-y: auto;
    background: var(--panel-title-bg, var(--bg-color, #14161f));
    border: 1px solid var(--panel-border, rgba(var(--tint, 255, 255, 255), 0.1));
    border-radius: 10px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
    padding: 4px 8px;
}

.dashboard-panels-popover.open {
    display: block;
}

/* Three columns (2026-08-24) — 25 catalog entries in a single list needed a lot of scrolling. */
#dashboard-panels-popover-body {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 0 8px;
}

.dashboard-panels-popover-handle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 8px;
    margin: -4px -8px 4px;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted, #94a3b8);
    cursor: move;
    user-select: none;
    border-bottom: 1px solid var(--panel-border, rgba(var(--tint, 255, 255, 255), 0.1));
}

/* Responsive reflow: on narrow viewports, multi-column spans collapse to fit screen width */
@media (max-width: 768px) {
    .bento-grid {
        grid-template-columns: 1fr;
        gap: var(--bento-gap-mobile, var(--bento-gap, 12px));
    }
    .bento-grid .bento-panel.bento-wide,
    .bento-grid .bento-panel.bento-span-2,
    .bento-grid .bento-panel.bento-span-3,
    .bento-grid .bento-panel.bento-hero,
    .bento-grid .bento-panel.bento-featured {
        grid-column: 1 / -1;
    }
}

/* Rows control (bento.js#wireRowsControls). Sits next to the panel title rather than in the
   action-button cluster, where a number input read as one more piece of chrome and crowded
   the resize/maximize/hide/collapse set. Straddles the same top border as the title, so
   it needs the same SOLID layered background — the old translucent rgba(0,0,0,0.25) let
   a solid/opaque --panel-border show straight through the input. The border property
   stays so it still reads as an input, not a label. */
.bento-rows-input {
    width: 44px;
    margin-left: 4px;
    padding: 1px 4px;
    font: inherit;
    font-size: 0.75rem;
    background-color: var(--panel-title-bg, var(--bg-color, #14161f));
    background-image: linear-gradient(var(--panel-bg, transparent), var(--panel-bg, transparent));
    border: 1px solid rgba(var(--tint, 255, 255, 255), 0.12);
    border-radius: 5px;
    color: var(--text-main, inherit);
}
.bento-panel.collapsed .bento-rows-input { display: none; }

/* Panel Types chrome & states (bento.js#wirePanelType) */
.bento-empty-state {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px 16px;
    color: var(--text-muted, #8b949e);
    font-size: 0.85rem;
    text-align: center;
}

.bento-list-overflow {
    font-size: 0.78rem;
    color: var(--text-muted, #8b949e);
    text-align: right;
    padding: 6px 4px 2px;
}

.bento-sort-th {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
.bento-sort-th:hover {
    color: var(--text-main, #e6edf3);
}
.bento-sort-indicator {
    display: inline-block;
    margin-left: 5px;
    font-size: 0.75rem;
    opacity: 0.6;
}
.bento-sort-th:hover .bento-sort-indicator,
.bento-sort-th.bento-sorted .bento-sort-indicator {
    opacity: 1;
}

.bento-log-pause-pill {
    position: sticky;
    bottom: 8px;
    left: 50%;
    transform: translateX(-50%);
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--panel-bg, #161b22);
    color: var(--text-main, #e6edf3);
    border: var(--hairline, 1px solid rgba(var(--tint, 255, 255, 255), 0.15));
    border-radius: 999px;
    padding: 4px 12px;
    font-size: 0.78rem;
    font-weight: 500;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    z-index: 10;
    width: fit-content;
    margin: 4px auto;
    transition: opacity 0.15s ease, transform 0.15s ease;
}
.bento-log-pause-pill:hover {
    background: var(--accent, #3b82f6);
    color: #fff;
}

.bento-stat {
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: -0.03em;
}
.bento-delta {
    font-size: 0.8rem;
    font-weight: 600;
}
.bento-delta.up { color: var(--ok, #22c55e); }
.bento-delta.down { color: var(--sale, #ef4444); }
.bento-sparkline {
    display: flex;
    align-items: flex-end;
    gap: 6px;
    height: 64px;
    margin-top: 8px;
}
.bento-sparkline i {
    flex: 1;
    background: var(--accent, #3b82f6);
    border-radius: 4px 4px 0 0;
    opacity: 0.85;
}

/* Drag matrix slot preview (Bento-2) */
.bento-grid.bento-drag-active {
    background-image: radial-gradient(color-mix(in srgb, var(--accent, #3b82f6) 15%, transparent) 1px, transparent 1px);
    background-size: 24px 24px;
}

/* ── Bento Size Settings (small / medium / large) ───────────────────────── */
.bento-panel.bento-small,
.bento-panel[data-bento-size="small"] {
    padding: 10px 12px;
    font-size: 0.82rem;
    min-height: 80px;
}
.bento-panel.bento-small .bento-panel-title,
.bento-panel[data-bento-size="small"] .bento-panel-title {
    font-size: 0.72rem;
    padding: 2px 6px;
    letter-spacing: 0.04em;
}
.bento-panel.bento-small .bento-panel-btn,
.bento-panel[data-bento-size="small"] .bento-panel-btn {
    width: 22px;
    height: 22px;
    font-size: 0.72rem;
}
.bento-panel.bento-small .bento-stat,
.bento-panel[data-bento-size="small"] .bento-stat,
.bento-panel.bento-small .stat,
.bento-panel[data-bento-size="small"] .stat {
    font-size: 1.5rem;
}

.bento-panel.bento-medium,
.bento-panel[data-bento-size="medium"] {
    padding: 16px 18px;
    font-size: 0.88rem;
}

.bento-panel.bento-large,
.bento-panel[data-bento-size="large"] {
    padding: 22px 24px;
    font-size: 0.95rem;
    min-height: 180px;
}
.bento-panel.bento-large .bento-panel-title,
.bento-panel[data-bento-size="large"] .bento-panel-title {
    font-size: 0.95rem;
    padding: 4px 10px;
}
.bento-panel.bento-large .bento-panel-btn,
.bento-panel[data-bento-size="large"] .bento-panel-btn {
    width: 30px;
    height: 30px;
    font-size: 0.95rem;
}
.bento-panel.bento-large .bento-stat,
.bento-panel[data-bento-size="large"] .bento-stat,
.bento-panel.bento-large .stat,
.bento-panel[data-bento-size="large"] .stat {
    font-size: 2.6rem;
}

/* Grid track sizing for small / medium / large */
.bento-grid .bento-panel.bento-large,
.bento-grid .bento-panel[data-bento-size="large"] {
    grid-column: span 2;
}
@media (min-width: 900px) {
    .bento-grid .bento-panel.bento-large,
    .bento-grid .bento-panel[data-bento-size="large"] {
        grid-column: span 3;
    }
}

/* ── Heading Placement Types ────────────────────────────────────────────── */
/* 1. on-frame (default): straddles the top border, already styled by .bento-panel-header */

/* 2. inside top-right */
.bento-panel.bento-header-top-right,
.bento-panel[data-bento-heading="top-right"],
.bento-panel[data-bento-header="top-right"] {
    padding-top: 14px !important;
}
.bento-panel.bento-header-top-right > .bento-panel-header,
.bento-panel[data-bento-heading="top-right"] > .bento-panel-header,
.bento-panel[data-bento-header="top-right"] > .bento-panel-header {
    top: 10px;
    right: 12px;
    left: auto;
    transform: none;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}
.bento-panel.bento-header-top-right > .bento-panel-header .bento-panel-title,
.bento-panel[data-bento-heading="top-right"] > .bento-panel-header .bento-panel-title,
.bento-panel[data-bento-header="top-right"] > .bento-panel-header .bento-panel-title {
    background: transparent;
    background-image: none;
    padding: 0 4px;
}
/* Inside headers sit within the panel, not on its border — no border to break, so the
   actions pill stays transparent here (matches the transparent title above). */
.bento-panel.bento-header-top-right > .bento-panel-header .bento-panel-actions,
.bento-panel[data-bento-heading="top-right"] > .bento-panel-header .bento-panel-actions,
.bento-panel[data-bento-header="top-right"] > .bento-panel-header .bento-panel-actions {
    background: transparent;
    background-image: none;
}
.bento-panel.bento-header-top-right > .bento-panel-content,
.bento-panel[data-bento-heading="top-right"] > .bento-panel-content,
.bento-panel[data-bento-header="top-right"] > .bento-panel-content {
    padding-top: 26px !important;
}

/* 3. inside bottom-right */
.bento-panel.bento-header-bottom-right,
.bento-panel[data-bento-heading="bottom-right"],
.bento-panel[data-bento-header="bottom-right"] {
    padding-top: 14px !important;
    padding-bottom: 38px !important;
}
.bento-panel.bento-header-bottom-right > .bento-panel-header,
.bento-panel[data-bento-heading="bottom-right"] > .bento-panel-header,
.bento-panel[data-bento-header="bottom-right"] > .bento-panel-header {
    top: auto;
    bottom: 8px;
    right: 12px;
    left: auto;
    transform: none;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}
.bento-panel.bento-header-bottom-right > .bento-panel-header .bento-panel-title,
.bento-panel[data-bento-heading="bottom-right"] > .bento-panel-header .bento-panel-title,
.bento-panel[data-bento-header="bottom-right"] > .bento-panel-header .bento-panel-title {
    background: transparent;
    background-image: none;
    padding: 0 4px;
}
/* Same as top-right: inside header, no border behind the icons. */
.bento-panel.bento-header-bottom-right > .bento-panel-header .bento-panel-actions,
.bento-panel[data-bento-heading="bottom-right"] > .bento-panel-header .bento-panel-actions,
.bento-panel[data-bento-header="bottom-right"] > .bento-panel-header .bento-panel-actions {
    background: transparent;
    background-image: none;
}
.bento-panel.bento-header-bottom-right > .bento-panel-content,
.bento-panel[data-bento-heading="bottom-right"] > .bento-panel-content,
.bento-panel[data-bento-header="bottom-right"] > .bento-panel-content {
    padding-bottom: 28px;
}

/* Collapsed state adjustments for inside top-right and bottom-right */
.bento-panel.collapsed.bento-header-top-right,
.bento-panel.collapsed[data-bento-heading="top-right"],
.bento-panel.collapsed[data-bento-header="top-right"],
.bento-panel.collapsed.bento-header-bottom-right,
.bento-panel.collapsed[data-bento-heading="bottom-right"],
.bento-panel.collapsed[data-bento-header="bottom-right"] {
    min-height: 48px;
}


