/*
 * core_ui / core-layout.css
 * ---------------------------------------------------------------------
 * Structural layout primitives: the spacing scale, page container,
 * section scaffolding, and flex/grid helpers. Mirrors the role
 * kd-base.css + kd-sections.css play together for khouse, staying
 * generic -- no tenant-specific component lives here, only shape.
 *
 * The spacing scale is the one place layout takes a tenant input:
 * --theme-space-unit (Theme.space_unit, default 4px, matching khouse's
 * 4px-based --kd-s-* scale) multiplies out into 12 steps the same way
 * kd-tokens.css's --kd-s-1..12 do, so a tenant that wants a visibly
 * roomier or tighter feel can change one number instead of retuning
 * every spacing value in its content templates.
 */
:root {
    --core-space-1:  calc(var(--theme-space-unit) * 1);
    --core-space-2:  calc(var(--theme-space-unit) * 2);
    --core-space-3:  calc(var(--theme-space-unit) * 3);
    --core-space-4:  calc(var(--theme-space-unit) * 4);
    --core-space-5:  calc(var(--theme-space-unit) * 5);
    --core-space-6:  calc(var(--theme-space-unit) * 6);
    --core-space-7:  calc(var(--theme-space-unit) * 8);
    --core-space-8:  calc(var(--theme-space-unit) * 10);
    --core-space-9:  calc(var(--theme-space-unit) * 12);
    --core-space-10: calc(var(--theme-space-unit) * 16);
    --core-space-11: calc(var(--theme-space-unit) * 20);
    --core-space-12: calc(var(--theme-space-unit) * 24);

    --core-container: 1240px;
    --core-container-pad: var(--core-space-6);

    /* Fixed elevation shadows -- ported from kd-tokens.css's
       --kd-shadow-1/--kd-shadow-2 concept, but flat neutral black rather
       than khouse's per-[data-theme] values: Theme.color_scheme (see
       core_ui/models.py) is a browser hint today, not a second full
       dark palette (that model field's own help_text explains why), so
       there's no per-mode fg/bg pair to key a tinted shadow off yet. A
       flat black-alpha shadow reads correctly on any surface color in
       the meantime, same as it does on most real design systems. */
    --core-shadow-1: 0 1px 0 rgba(0, 0, 0, 0.04);
    --core-shadow-2: 0 12px 28px -16px rgba(0, 0, 0, 0.18);
}

.core-container {
    width: 100%;
    max-width: var(--core-container);
    margin-inline: auto;
    padding-inline: var(--core-container-pad);
}

/* ---- Section scaffolding ---- */
.core-section           { padding-block: var(--core-space-10); }
/* Breadcrumbed sections share the same tighter header rhythm across the
 * generic pages; the wrapper owns page geometry, not the nav component. */
section:has(> .core-container > nav.core-breadcrumb) {
    padding-block: var(--core-space-6) var(--core-space-8);
}
.core-section--alt      { background: var(--theme-bg-alt); }
.core-section--sunken   { background: var(--theme-bg-sunken); }
/* A bordered section owns its whole block-start boundary: space between
 * the preceding content and the divider border, then a tighter space
 * under the border before its own content -- the wrapper is the spacing
 * owner, headings inside it stay margin 0 (core-reset.css). Standalone
 * (product detail's sub-sections) this is the entire contract; paired
 * with .core-section (a post body; cta_banner.html's pattern) the base
 * class adds the block-end padding that keeps the page's last cards off
 * the footer band, and this later rule tightens only the start side. */
.core-section--bordered {
    border-top: 1px solid var(--theme-border);
    margin-block-start: var(--core-space-10);
    padding-block-start: var(--core-space-8);
}

.core-section__head         { margin-bottom: var(--core-space-8); }
.core-section__head--center { text-align: center; max-width: 720px; margin-inline: auto; }

.core-rule { border: 0; height: 1px; background: var(--theme-border); margin: 0; }

/* ---- Flex/grid primitives ---- */
.core-stack { display: flex; flex-direction: column; gap: var(--core-space-4); }
.core-stack--tight { gap: var(--core-space-1); }
.core-row   { display: flex; align-items: center; gap: var(--core-space-3); flex-wrap: wrap; }
.core-row:is(a) { min-height: 44px; }
.core-row--split { justify-content: space-between; }

.core-grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--core-space-6); }
.core-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--core-space-6); }
.core-grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--core-space-6); }

/* Mobile-first collapse -- every multi-column grid degrades to fewer
   columns, then one, well before content has to shrink to fit
   (DOCTRINE.md: mobile-optimized throughout). */
@media (max-width: 1024px) {
    .core-grid-3, .core-grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
    .core-grid-2, .core-grid-3, .core-grid-4 { grid-template-columns: 1fr; }
    .core-container { --core-container-pad: var(--core-space-4); }
}

/* ---- Sidebar + main layout ----
   A narrow, sticky-on-desktop rail beside the main content column -- the
   shape any filtered listing page (a faceted catalogue, a filtered
   article index, ...) needs, so it lives here as a generic primitive
   rather than being reinvented per app. Collapses to a single column
   (sidebar first, matching source order) well before mobile. */
.core-layout-sidebar {
    display: grid;
    grid-template-columns: 260px 1fr;
    gap: var(--core-space-8);
    align-items: start;
}
/* A data table may be wider than its phone viewport inside an explicit
 * scroll region. Grid items otherwise use their content's automatic
 * minimum width, which pushes the whole document wide before that region
 * can scroll. Let the region own the overflow instead. */
.core-layout-sidebar > * { min-width: 0; }
/* The sticky sidebar has to clear the sticky HEADER, which sits at
 * top: 0 with z-index 100 (core-nav.css). Sticking this at
 * var(--core-space-6) put it 24px from the VIEWPORT, i.e. underneath the
 * header, so scrolling slid the account nav behind the masthead and cut
 * its first entries off.
 *
 * --core-header-height is declared rather than measured, because CSS
 * cannot read another element's computed height. It is defined ONCE in
 * core-nav.css next to the header whose size it describes, so the two
 * cannot drift apart in separate files. */
.core-layout-sidebar__aside {
    position: sticky;
    top: calc(var(--core-header-height) + var(--core-space-4));
    /* Below the header, deliberately: if they ever do overlap, the
     * header wins rather than the sidebar painting over the logo. */
    z-index: 1;
    /* A nav taller than the viewport must scroll on its own, or its last
     * entries become unreachable once it is stuck. */
    max-height: calc(100vh - var(--core-header-height) - var(--core-space-8));
    overflow-y: auto;
}
.core-facet-drawer { min-width: 0; }
.core-facet-drawer__summary { display: none; }
@media (max-width: 900px) {
    .core-layout-sidebar { grid-template-columns: 1fr; }
    .core-layout-sidebar__aside { position: static; }
    .core-facet-drawer {
        border: 1px solid var(--theme-border);
        border-radius: var(--theme-radius);
        background: var(--theme-surface, var(--theme-bg));
    }
    .core-facet-drawer__summary {
        display: flex;
        align-items: center;
        justify-content: space-between;
        min-height: var(--core-touch-min);
        padding: var(--core-space-2) var(--core-space-3);
        cursor: pointer;
        font-family: var(--theme-font-mono);
        font-size: var(--core-text-1);
    }
    .core-facet-drawer__indicator::after { content: "+"; font-size: var(--core-text-3); }
    .core-facet-drawer[open] .core-facet-drawer__indicator::after { content: "−"; }
    .core-facet-drawer__body { padding: 0 var(--core-space-3) var(--core-space-3); }
}
@media print {
    /* A closed native disclosure hides its body on screen. Printed output
     * must retain the available filters rather than silently omitting them. */
    .core-facet-drawer:not([open]) .core-facet-drawer__body { display: block !important; }
    .core-facet-drawer__summary { display: none; }
}
