/* sidebar-layout.css — the shared sidebar frame (controls/sidebar-layout/).
 *
 * Every selector is namespaced under .lp-sidebar. That is what makes this file
 * safe to link globally while three apps are mid-adoption: no app gets restyled
 * until it opts in by mounting the component. Same discipline spaces-tree.css
 * used, and the reason index.html can carry the <link> from P0.
 *
 * THE VALUES WERE CHAT'S, COPIED — not re-derived. Per the owner ruling, Chat
 * was the reference, so:
 *   - the header height started at Chat's 44px and is now 46px — the FIRST
 *     value here the component owns rather than inherits (owner ruling,
 *     2026-09-16, after seeing both apps side by side). Chat moves with it,
 *     which is the point: one header height, one place to change it, instead
 *     of the 44/48/auto spread §2 of the arc measured.
 *   - 14px/600 title, from shell.css:435  (Signal overrides to 15px)
 *   - the header button, from shell.css:438
 *   - 42px primary row + 10px gap, from chat-features.css:873,897
 *   - 8px body padding + 2px row gap, from chat-features.css:95
 * P1's gate WAS that Chat's sidebar differed in no pixel after adopting this,
 * so that the adoption could be reviewed as a refactor rather than a redesign.
 * That gate has served its purpose and is now spent: the header height is a
 * deliberate 46px, and Chat moved with it.
 *
 * The discipline it protected still holds, and is the thing to keep: a value
 * here changes ONCE, on purpose, for every app at the same time. What the gate
 * forbade was inventing values silently during an adoption — not the component
 * ever having an opinion of its own.
 *
 * NOT in core.css. That file carries a second copy of the .sidebar-header block
 * and is not linked by index.html — only controls-lab loads it — so a rule put
 * there resolves to nothing in the app. See .claude/rules/ui-design-scope.md.
 */

/* No `height` here on purpose. When the frame ADOPTS its host (the default),
   this class lands on an element the app already sized — #sidebar is a flex
   child of the app shell whose height comes from that row, and a 100% against
   an auto-height parent would resolve to auto and collapse the body. The frame
   only asserts that its regions stack in a column and that the body may shrink
   below its content; the host keeps owning how tall it is. */
.lp-sidebar {
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

/* ── Header ──────────────────────────────────────────────────────────── */

.lp-sidebar-header {
    /* 46px is the component's own value, not Chat's 44px — see the header note
       at the top of this file. Owner ruling, 2026-09-16. */
    height: 46px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 14px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}

/* The title scale is HERE, not in an app sheet.
 *
 * 17px/700 was a Chat-only override (`#sidebar:has(#sidebar-signal-list)
 * .sidebar-title`, chat-features.css:10) while this rule said 14px/600 — so an
 * app that adopted the frame got the smaller title and had to discover the
 * difference by eye. Same shape of mistake as the nav row scale, and the same
 * fix: if a region belongs to the frame, its typography does too. An app that
 * genuinely wants to differ overrides it deliberately, rather than being
 * defaulted into a look nobody chose. */
.lp-sidebar-title {
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text-primary);
    /* A long title truncates rather than pushing the actions off the edge —
       the actions are the only way to collapse the sidebar. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lp-sidebar-header-actions {
    display: flex;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
}

/* Likewise the button box: 30px with an 18px glyph, which was also Chat-only
   (chat-features.css:15). A fixed square rather than padding so the two buttons
   line up whatever glyph an app puts in them. */
.lp-sidebar-header-btn {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-secondary);
    width: 30px;
    height: 30px;
    padding: 0;
    border-radius: 7px;
    font-size: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.lp-sidebar-header-btn:hover {
    color: var(--text-primary);
    background: var(--bg-hover);
}
/* CSS has to outrank the width/height attributes an inline svg carries, or each
   app's own glyph markup decides its own size — which is how Chaos ended up with
   14px icons beside Chat's 18px ones. */
.lp-sidebar-header-btn svg {
    width: 18px;
    height: 18px;
}

/* ── Below-header band ───────────────────────────────────────────────── */

/* For a control that belongs to the whole sidebar rather than to either view —
   Chaos's search field. Pinned, like everything above the body, and padded like
   every other band so whatever it holds lines up with the rows below. */
.lp-sidebar-subheader {
    flex-shrink: 0;
    padding: 8px 8px 0;
}
.lp-sidebar-subheader:empty {
    display: none;
}

/* ── Primary action ──────────────────────────────────────────────────── */

/* Pinned: it must not scroll away with the list below it. The 8px sides mirror
   the body's padding so the pill lines up with the rows beneath. */
.lp-sidebar-primary {
    flex-shrink: 0;
    padding: 8px 8px 0;
}

.lp-sidebar-primary-row {
    display: flex;
    gap: 10px;
    align-items: stretch;
}

/* The pill itself is .lani-sidebar-new-btn (lani-ui.css) — shared, and already
   worn by Chat and Signal. All this adds is filling the row. */
.lp-sidebar-primary-btn {
    flex: 1;
    min-width: 0;
}

/* A 42x42 square beside the 42px-tall pill, not a shorter icon chip. */
.lp-sidebar-primary-aux {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 42px;
    height: 42px;
    padding: 0;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--bg-surface);
    color: var(--text-primary);
    cursor: pointer;
    transition: background 0.15s, box-shadow 0.15s;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
}
.lp-sidebar-primary-aux:hover {
    background: var(--bg-hover);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
.lp-sidebar-primary-aux svg {
    width: 17px;
    height: 17px;
    color: var(--text-primary);
}
.lp-sidebar-primary-aux:disabled {
    cursor: default;
    opacity: 0.7;
}

/* ── Nav ─────────────────────────────────────────────────────────────── */

/* Rows are .lp-sidenav* (sidebar-nav.css) — shared. This is only the region. */
.lp-sidebar-nav {
    flex-shrink: 0;
    padding: 8px 8px 0;
}

/* ── View switch ─────────────────────────────────────────────────────── */

/* The switch is .lp-sidebar-view-switch (sidebar-nav.css) — shared, and it sits
   OUTSIDE the body on purpose: the body's sections show and hide, and a control
   with a sliding thumb must not live in a region that changes. */
.lp-sidebar-switch {
    flex-shrink: 0;
    padding: 8px 8px 0;
}
/* An app mid-adoption may own its own switch instance (showSwitch:false), which
   leaves this host empty. It must then take no space at all — padding on an
   empty box is still 8px of gap the app never had. */
.lp-sidebar-switch:empty {
    display: none;
}

/* ── Body: two sections ──────────────────────────────────────────────── */

/* Only present when there are two sections to arrange. With one, the section IS
   the body and is a flex child of .lp-sidebar directly — which is why the
   `flex: 1` below is on the SECTION rather than here: it has to work in both
   positions, nested in this wrapper or sitting in the frame. */
.lp-sidebar-body {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* Each section scrolls itself. That is what lets the two keep independent
   scroll positions across a toggle — one shared scroller has one scrollTop and
   two meanings for it. */
.lp-sidebar-section {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 8px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.lp-sidebar-section[hidden] {
    display: none;
}
.lp-sidebar-section::-webkit-scrollbar { width: 6px; }
.lp-sidebar-section::-webkit-scrollbar-track { background: transparent; }
.lp-sidebar-section::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.lp-sidebar-section::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

/* ── Footer ──────────────────────────────────────────────────────────── */

/* Chat has none. Chaos stacks its cloud CTA and sync indicator here. */
.lp-sidebar-footer {
    flex-shrink: 0;
    border-top: 1px solid var(--border);
}

/* ── Collapsed ───────────────────────────────────────────────────────── */

/* Deliberately NO display/width rule here. The frame only STAMPS the collapsed
   state; the column owns what collapsing looks like, because only it knows what
   it is collapsing against — .sidebar.collapsed in shell.css:426 animates width
   and min-width to zero, and a display:none on the same element would kill that
   transition outright. An app that has no such rule of its own can hang one off
   this class. */
