/* =============================================================================
   KTHX -- console shell: sidebar, top bar, tab strip, phone bottom bar
   (workbench/license#136, "The shell")

   Layers on top of app.css and uses the same theme tokens. One 240px sidebar
   replaced the 72px icon rail and the 232px secondary panel; a module's
   secondary pages became tabs in its page header (render_page_tabs()).
   ========================================================================== */

:root {
    --sidebar-w: 240px;
    --topbar-h:  52px;
    --bottomnav-h: 60px;          /* phone bottom bar, excluding the safe area */
    --side:      #fafafb;         /* the sidebar ground, a step off --panel */
}
:root[data-theme="dark"] { --side: #111318; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) { --side: #111318; }
}

/* The console has no sticky footer (#136): the version moved into the
   sidebar. Zeroed rather than deleted so the calc()s that subtract it --
   Smart Licenses, the split-detail pane -- keep working unchanged. */
body.app { --footer-h: 0px; }

/* ---- Shell --------------------------------------------------------------- */

.shell {
    display: flex;
    align-items: flex-start;
    min-height: 100vh;
}

/* Everything right of the sidebar. A column, so the top bar sits over the
   content only -- the sidebar runs the full height beside it, as in the
   mockups. min-width:0 lets wide tables scroll inside .main rather than
   widening the page. */
.shell-main {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}
.shell-main > .main { width: 100%; }
.shell-main > .main-full { flex: 1 1 auto; }

/* ---- Sidebar ------------------------------------------------------------- */

.sidebar {
    position: sticky;
    top: 0;
    flex: 0 0 var(--sidebar-w);
    width: var(--sidebar-w);
    height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--side);
    border-right: 1px solid var(--border);
    font-size: var(--text-md);
    z-index: 31;
}

.sb-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 16px 12px;
}
.sb-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--fg-muted);
    text-decoration: none;
}
.sb-brand:hover { text-decoration: none; color: var(--fg); }
.sb-mark { width: 36px; height: 36px; flex: 0 0 auto; display: block; }
.sb-brand-text { font-size: var(--text-sm); font-weight: 500; line-height: 1.2; }
.sb-close { display: none; }   /* the drawer's close control, phone only */

.sb-search {
    display: flex;
    align-items: center;
    gap: 6px;
    height: 32px;
    margin: 0 12px 12px;
    padding: 0 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-panel);
    color: var(--fg-muted);
}
.sb-search:hover { text-decoration: none; border-color: var(--fg-dim); color: var(--fg); }
.sb-search svg { width: 14px; height: 14px; flex: 0 0 auto; }
.sb-search-text { flex: 1 1 auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sb-kbd {
    /* 10px and tight padding so "Ctrl K" (palette.js swaps it in off macOS)
       fits beside the full "Search or jump to…" in the 240px sidebar (#136). */
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-size: 10px;
    padding: 0 4px;
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--fg-muted);
}

/* The module list scrolls on its own, so a long list of linked apps never
   pushes Settings and the user block off the bottom. */
.sb-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0 8px 12px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.sb-section { display: flex; flex-direction: column; gap: 1px; }

/* The eighth copy of the small-caps label (see the note on .page-head-meta's
   neighbours in app.css): --fg-muted, not --fg-dim, which is decoration
   only and fails 4.5:1 at this size. */
.sb-title {
    padding: 4px 8px;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--fg-muted);
}

.sb-item {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 30px;
    padding: 0 8px;
    border-radius: var(--radius);
    color: var(--fg);
    text-decoration: none;
    font-family: inherit;
    font-size: inherit;
}
.sb-item:hover { background: var(--bg-hover); text-decoration: none; }
.sb-item svg { width: 16px; height: 16px; flex: 0 0 auto; color: var(--fg-muted); }
.sb-label { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; line-height: 1.25; padding: 5px 0; }
.sb-item.is-active { background: var(--accent-soft); color: var(--accent); font-weight: 500; }
.sb-item.is-active svg { color: var(--accent); }
.sb-item.is-disabled { color: var(--fg-dim); opacity: .55; cursor: default; }
.sb-item.is-disabled:hover { background: none; }

/* Problem count at the right of an entry (#136; src/nav_badges.php): the
   status vocabulary's crit/warn pair, soft ground and strong text, as .pill
   draws them, plus .is-info (blue) for waiting work -- a zero draws nothing. */
.sb-badge {
    flex: 0 0 auto;
    min-width: 18px;
    padding: 1px 6px;
    border-radius: 10px;
    font-size: var(--text-xs);
    font-weight: 600;
    line-height: 16px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
.sb-badge.is-crit { background: var(--crit-soft); color: var(--crit); }
.sb-badge.is-warn { background: var(--warn-soft); color: var(--warn); }
.sb-badge.is-info { background: var(--info-soft); color: var(--info); }
.sb-badge + .sb-badge { margin-left: 4px; }

.sb-foot {
    flex: 0 0 auto;
    padding: 10px 8px 10px;
    border-top: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.sb-user { display: flex; align-items: center; gap: 4px; padding: 8px 0 2px 8px; }
.sb-user-link {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--fg);
}
.sb-user-link:hover { text-decoration: none; }
.sb-user-link:hover .sb-user-name { color: var(--accent); }
.sb-avatar {
    width: 26px;
    height: 26px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: var(--text-xs);
}
.sb-user-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.sb-user-name { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sb-user-sub { font-size: var(--text-xs); color: var(--fg-muted); }
.sb-signout-form { display: contents; }
.sb-signout {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: 0;
    border-radius: var(--radius);
    color: var(--fg-muted);
    cursor: pointer;
}
.sb-signout:hover { background: var(--bg-hover); color: var(--fg); }
.sb-signout svg { width: 16px; height: 16px; }
.sb-version { padding: 6px 8px 0; font-size: var(--text-xs); color: var(--fg-muted); }

/* ---- Top bar ------------------------------------------------------------- */

/* app.css .topbar gives the bar its height, ground and stickiness; here it
   holds the breadcrumb instead of the old brand + user. */
.shell-main > .topbar { padding: 0 24px; gap: 12px; }
.topbar-brand { display: none; }                 /* phone only, see below */
.topbar-mark { width: 28px; height: 28px; display: block; }

.crumbs {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    font-size: var(--text-md);
    white-space: nowrap;
}
.crumb-section, .crumb-link { color: var(--fg-muted); }
.crumb-link:hover { color: var(--accent); }
.crumb-sep { color: var(--fg-dim); }
.crumb-page { font-weight: 500; color: var(--fg); overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* ---- Tab strip (render_page_tabs) ----------------------------------------
   The .tabs / .tab-list / .tab component itself is defined in monitoring.css
   (it started on the node page, #77 §15). Here it sits under the page
   heading, beside a right-hand cluster for the Manage menu and the licence
   Group picker. The border moves from the scroller to the row, so the
   cluster sits on the same rule; the cluster is outside the scroller because
   an overflow-x box clips an absolutely-positioned menu. */

.page-tabs {
    display: flex;
    align-items: flex-end;
    gap: var(--space-4);
    margin: calc(-1 * var(--space-1)) 0 var(--space-5);
    border-bottom: 1px solid var(--border);
}
.page-tabs > .tabs {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    border-bottom: 0;
}
.page-tabs .tab { font-size: var(--text-md); }
/* The first admin tab, when there are too few for a menu, stands apart. */
.tab-list > .tab-gap { margin-left: 12px; padding-left: 20px; border-left: 1px solid var(--border); }
.tab-list > .tab-gap { align-self: center; }

.page-tabs-end {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding-bottom: 6px;
}

.tab-menu { position: relative; }
.tab-menu-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 30px;
    padding: 0 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-panel);
    color: var(--fg-muted);
    font-size: var(--text-md);
    cursor: pointer;
    list-style: none;
    white-space: nowrap;
    user-select: none;
}
.tab-menu-btn::-webkit-details-marker { display: none; }
.tab-menu-btn::marker { content: ""; }
.tab-menu-btn:hover { color: var(--fg); border-color: var(--fg-dim); }
.tab-menu-btn svg { width: 14px; height: 14px; flex: 0 0 auto; }
.tab-menu-btn strong { color: var(--fg); font-weight: 500; }
.tab-menu[open] > .tab-menu-btn,
.tab-menu.is-current > .tab-menu-btn { border-color: var(--accent); color: var(--accent); }

.tab-menu-list {
    position: absolute;
    right: 0;
    top: calc(100% + 4px);
    z-index: 40;
    min-width: 200px;
    margin: 0;
    padding: 4px;
    list-style: none;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-3);
}
.tab-menu-item {
    display: block;
    padding: 6px 10px;
    border-radius: var(--radius);
    color: var(--fg);
    white-space: nowrap;
}
.tab-menu-item:hover { background: var(--bg-hover); text-decoration: none; }
.tab-menu-item.is-current { background: var(--accent-soft); color: var(--accent); font-weight: 500; }

/* The Group picker holds a tree, so it is wider and scrolls. */
.tab-menu-tree { width: 320px; max-height: min(60vh, 520px); overflow-y: auto; padding: 8px; }

/* ---- Phone bottom bar: off on desktop ------------------------------------ */
.bottomnav { display: none; }

/* ---- Phone (<= 860px) -----------------------------------------------------
   The sidebar becomes a drawer that the bottom bar's More opens, and a fixed
   five-slot bottom bar takes the rail's old job (#136, #135 §20).

   The drawer is hidden with visibility as well as a transform. The old
   subnav drawer was only translated off-screen, so its box-shadow still
   painted a grey strip down the left edge of every page (#135 §20); here the
   shadow exists only while it is open. It opens on .open (app.js) and on
   :target (the More link is href="#sidebar"), so it works with scripts off.
   -------------------------------------------------------------------------- */

@media (max-width: 860px) {
    .shell { display: block; min-height: 0; }
    .shell-main { min-height: 100vh; }

    .sidebar {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        width: min(300px, 86vw);
        height: auto;
        z-index: 60;
        transform: translateX(-100%);
        visibility: hidden;
        transition: transform .18s ease, visibility 0s linear .18s;
    }
    .sidebar.open,
    .sidebar:target {
        transform: none;
        visibility: visible;
        transition: transform .18s ease;
        /* The scrim: one enormous spread shadow, so the drawer needs no second
           element to dim the page behind it. */
        box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .35);
    }
    .sb-close {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 40px;
        height: 40px;
        margin-right: -8px;
        color: var(--fg-muted);
    }
    .sb-close svg { width: 20px; height: 20px; }
    .sb-item { min-height: 40px; }

    .shell-main > .topbar { padding: 0 12px; }
    .topbar-brand { display: block; flex: 0 0 auto; }
    /* Only the last crumb: at 390px the whole trail would ellipsize to
       nothing, and the bottom bar already says which module this is. */
    .crumbs > :not(:last-child) { display: none; }

    .page-tabs { flex-wrap: wrap; gap: 0 var(--space-2); }
    .page-tabs-end { padding: 6px 0; }
    .tab-menu-list { right: auto; left: 0; }
    .page-tabs-end > .tab-menu:last-child .tab-menu-list { right: 0; left: auto; }
    .tab-menu-tree { width: min(320px, calc(100vw - 32px)); }

    .bottomnav {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 50;
        display: grid;
        grid-template-columns: repeat(5, minmax(0, 1fr));
        height: calc(var(--bottomnav-h) + env(safe-area-inset-bottom, 0px));
        padding-bottom: env(safe-area-inset-bottom, 0px);
        background: var(--bg-panel);
        border-top: 1px solid var(--border);
    }
    .bn-item {
        position: relative;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        min-width: 0;
        color: var(--fg-muted);
        text-decoration: none;
    }
    .bn-item:hover { text-decoration: none; color: var(--fg); }
    .bn-item svg { width: 22px; height: 22px; }
    /* The icon's box, so a problem count can sit on its corner. */
    .bn-icon { position: relative; display: inline-flex; }
    /* Solid, not soft: at this size on a bar the soft ground disappears. White
       on --crit/--warn only in light; dark's tokens are light tints, so the
       text there is the panel colour. */
    .bn-badge {
        position: absolute;
        top: -4px;
        right: -9px;
        min-width: 16px;
        height: 16px;
        padding: 0 4px;
        border-radius: 8px;
        font-size: 10px;
        font-weight: 600;
        line-height: 16px;
        text-align: center;
        color: var(--bg-panel);
        font-variant-numeric: tabular-nums;
    }
    .bn-badge.is-crit { background: var(--crit); }
    .bn-badge.is-warn { background: var(--warn); }
    .bn-badge.is-info { background: var(--info); }
    .bn-label {
        font-size: var(--text-xs);
        max-width: 100%;
        padding: 0 2px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .bn-item.is-active { color: var(--accent); font-weight: 600; }

    /* Keep content clear of the bar. */
    body.app .main {
        padding-bottom: calc(var(--bottomnav-h) + env(safe-area-inset-bottom, 0px) + 1.5rem);
    }
    body.app .main-full {
        padding-bottom: calc(var(--bottomnav-h) + env(safe-area-inset-bottom, 0px));
    }
}

/* ---- Browse list polish (group browse / My Licenses) --------------------- */

.split-list .asset-list {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-panel);
    box-shadow: var(--shadow);
    overflow: hidden;
}
.split-list .asset-list .asset-row { padding: .6rem .8rem; }
.split-list .asset-list .asset-row:hover { background: var(--bg-hover); }

/* ---- Desktop defaults for the phone-only pieces -------------------------- */
.crumb-back { display: none; }        /* the back chevron, phone only */
.sb-theme { display: none; }          /* the drawer's theme picker, phone only */
.app-bar-tools { display: none; }     /* search + ⋯ in the page head, phone only */

/* =============================================================================
   Phones (#136 mobile) -- the app bar

   Same single breakpoint as app.css's "Phones" section: (max-width: 699px);
   see the note there. Everything below is scoped to it, so the tablet layout
   (the 860px block above) and every desktop render exactly as before.

   On a phone the page head IS the app bar (MApp board): a large title with
   the count under it, and at the right search and a ⋯ that opens the action
   sheet (app.js). The sheet carries the head's actions, the module's tabs
   (as "Views") and its Manage / Group menus, so none of those is drawn
   inline and nothing scrolls sideways. Anything in the head marked
   .keep-mobile stays in the bar (Nodes' "Select", for one).

   The top bar gives way to it: on a module's own pages there is nothing for
   the top bar to say that the app bar does not, so it goes; on a detail page
   it stays as the back bar ("‹ Nodes"), the breadcrumb's module link. Its
   theme picker moves into the drawer.
   ========================================================================== */

@media (max-width: 699px) {
    /* ---- Top bar: safe area, back button, or nothing ----------------------- */
    .shell-main > .topbar {
        height: calc(var(--topbar-h) + env(safe-area-inset-top, 0px));
        padding: env(safe-area-inset-top, 0px) max(12px, env(safe-area-inset-right, 0px)) 0 max(12px, env(safe-area-inset-left, 0px));
    }
    .topbar-right .theme-pick { display: none; }
    .shell-main:has(.main .page-head):not(:has(.crumb-link)) > .topbar { display: none; }

    .crumb-back { display: inline-flex; margin-left: -8px; }
    .crumb-back svg { width: 26px; height: 26px; }
    .crumbs > .crumb-link {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        padding-right: 8px;
        color: var(--accent);
        font-size: 16px;
        font-weight: 500;
    }
    .crumbs:has(.crumb-link) > :not(.crumb-link) { display: none; }
    .crumbs:has(.crumb-link) ~ .topbar-right { display: none; }
    .topbar:has(.crumb-link) > .topbar-brand { display: none; }

    /* ---- The app bar --------------------------------------------------------
       Pinned to the top as the mockup's is, on the pages where it replaced
       the top bar; under a back bar it scrolls with the page. */
    .main { padding-left: max(16px, env(safe-area-inset-left, 0px)); padding-right: max(16px, env(safe-area-inset-right, 0px)); }
    .main .page-head {
        align-items: center;
        gap: 4px 8px;
        margin: 0 0 var(--space-3);
    }
    html.js .main .page-head { flex-wrap: nowrap; }
    .shell-main:not(:has(.crumb-link)) .main .page-head {
        position: sticky;
        top: 0;
        z-index: 25;
        margin: -1rem -16px var(--space-3);
        padding: calc(10px + env(safe-area-inset-top, 0px)) 8px 8px 16px;
        background: var(--bg);
    }
    .page-head-main {
        flex: 1 1 auto;
        flex-direction: column;
        align-items: flex-start;
        flex-wrap: nowrap;
        gap: 1px;
    }
    .page-head h1 {
        margin: 0;
        font-size: 26px;
        line-height: 1.15;
        letter-spacing: -.02em;
        overflow-wrap: anywhere;
    }
    .page-head-meta { font-size: 13px; }
    html.js .page-head-actions { flex: none; flex-wrap: nowrap; margin-left: 0; gap: 0; }
    .app-bar-tools { display: flex; flex: none; align-items: center; }
    .app-bar-btn[hidden] { display: none; }
    .app-bar-btn { border-radius: 22px; color: var(--fg); }
    .app-bar-btn svg { width: 22px; height: 22px; }
    .page-head-actions > .keep-mobile { min-height: 44px; }

    /* With scripts on, the head's actions and the whole tab strip live in the
       action sheet; with them off both stay inline and wrap (below). */
    html.js .page-head-actions > :not(.keep-mobile) { display: none; }
    html.js .page-head-actions:not(:has(.keep-mobile)) { display: none; }
    html.js .page-tabs { display: none; }

    /* Scripts off: the strip wraps instead of scrolling, and a menu opens in
       place (app.css). */
    .page-tabs { flex-wrap: wrap; align-items: stretch; }
    .page-tabs > .tabs { overflow: visible; flex: 1 1 100%; }
    .page-tabs .tab-list { flex-wrap: wrap; min-width: 0; gap: 0 18px; }
    .page-tabs .tab { min-height: 44px; }
    .page-tabs-end { flex: 1 1 100%; flex-wrap: wrap; }
    .tab-menu { width: 100%; }
    .tab-menu-btn { min-height: 44px; width: 100%; }
    .tab-menu-list, .tab-menu-tree { width: 100%; }

    /* Any other tab strip (a node's sections) wraps as well: nothing on a
       phone scrolls sideways. */
    .tabs { overflow: visible; }
    .tab-list { flex-wrap: wrap; min-width: 0; column-gap: 18px; }
    .tab { min-height: 44px; }

    /* ---- The drawer: touch-sized, and home to the theme picker ------------ */
    .sidebar {
        padding-top: env(safe-area-inset-top, 0px);
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }
    .sb-item { min-height: 44px; }
    .sb-search { height: 44px; }
    .sb-signout { width: 44px; height: 44px; }
    .sb-theme {
        display: flex;
        align-items: center;
        gap: 10px;
        margin: 6px 0 0;
        padding: 0 0 0 8px;
        font-weight: 400;
        color: var(--fg-muted);
    }
    .sb-theme-label { flex: 1 1 auto; }
    .sb-theme select { width: auto; flex: none; }

    /* ---- Bottom bar: full-height targets ----------------------------------- */
    .bn-item { min-height: 44px; }
    .bn-label { font-size: 11px; }
}
