/* Shared component rules — Shell-owned, linked once in App.razor's <head>, available to every Blick regardless
   of its own AssemblyLoadContext (a CLR-load boundary, not a DOM one — the rendered page is one DOM tree, so a
   plain global stylesheet reaches every Blick's markup same as app.css/theme.css already do). One home instead
   of a per-surface copy (Story 7, 2026-08-02 — Brian ratified Arthur's approach).

   Renamed from shared.css, stage 5 of the layer split (Sprint 9.5 Story 22,
   architecture/SHARED-CSS-LAYER-SPLIT.md) — this is the page-level chrome that stayed behind once navigation,
   forms, dialogs, readonly, grid and vendor rules each moved to their own file: the section control row, page
   header panel, breadcrumb, and the detail-screen carpet family.

   ── Section control row (.app-controls) ──────────────────────────────────────────────────────────────────
   THE one control row for a section landing screen — the strip of view/filter pills, dropdowns and action
   buttons that sits directly under the page <h1>. Brian approved the Quotes screen's version of this
   (CCP.QuoteContext.Blick/Pages/Quotes.razor, 2026-08-19) and ruled it the app-wide look, so the three forks
   that existed alongside it were collapsed onto it (DESIGN-SYSTEM.md §4.32): .app-tabstrip/.app-tab as used by the Products
   and System chromes, .inv-cluster-nav/.inv-cluster__tab as used by the Inventory chrome, and the Quote
   Blick's own .qw-controls — all now render this rule plus Bootstrap's own `btn btn-sm btn-primary`
   (active) / `btn btn-sm btn-outline-secondary` (inactive) pills, exactly as Quotes already did. The values
   below are .qw-controls' values verbatim so the approved screen comes out pixel-identical.

   .app-tabstrip/.app-tab BELOW is a different control and deliberately survives: real in-page tabs
   (role="tab" + a tabpanel that swaps in place) on ProductOptions, CustomerEditor, CustomerProfile and
   VendorDetails. A control row navigates to another page; a tabstrip swaps a panel — one look each, not one
   look for both.

   RULED 2026-09-01 (Brian): the ACTIVE pill deliberately keeps the btn-primary fill, the same token an action
   button uses. This was raised as a blocking visual finding (F13 — "selected tab uses the primary-action
   token") and ACCEPTED AS A RED MARK: three grouped pills with exactly one filled is the standard Bootstrap
   tabs idiom, an action button never appears in that position, the accessible name carries the active state
   independently of colour (aria-current="page"), and the worst case is a no-op click on the tab you are already
   on. Changing it would move the pixels of the Quotes screen approved 2026-08-19 and force re-inspection of all
   four converged rows. DO NOT "fix" this, and do not add a second active-state token.
   The ONE condition that reopens it: a control row carrying a SINGLE tab, which would render one lone filled
   pill with nothing to compare it against. None exists today; if one is ever built, add a non-colour affordance
   (inset underline or reduced hover) to .active at that point — that is additive and reverses nothing here.
   Full finding + reasoning: backlog/plan_will-2026-08-28-finance-visual-inspection.md, F13.
   2026-09-02: .content top padding 1.1rem -> --brand-space-4 moved every page, Quotes included, by 1.6px;
   accepted by the lead without re-inspection.
   2026-09-02 (DESIGN-SYSTEM-GRIDS-AND-DIALOGS.md §11.4b): this ruling is NOT superseded by the segmented
   filter below. A control row that NAVIGATES (this ruling's subject) keeps the btn-primary/btn-outline-secondary
   pills; a control row that FILTERS a grid is a different control (.btn-group[role="radiogroup"]) that this
   ruling never addressed. Quotes.razor's own status row moved to the segmented control because it filters,
   not because F13 was reopened. */
.app-controls {
    display: flex;
    gap: var(--brand-space-3);
    align-items: center;
    margin-bottom: var(--brand-space-4);
    flex-wrap: wrap;
}
/* A select in a controls row sits beside its label at its content's width. Bootstrap's .form-select is width: 100%, which
   in this wrapping row pushes it onto its own full-width line (seen on Defined Lists' "Type:" picker, 2026-10-05). */
.app-controls > .form-select {
    width: auto;
}
/* Same trap for the search box: Bootstrap's .input-group is width: 100%, so inside this wrapping row it drops onto a line of its own. */
.app-controls > .list-search {
    width: auto;
    flex: 0 1 18rem;
    min-width: 12rem;
}

/* ── Bootstrap's own .text-muted, retuned (L-256) ─────────────────────────────────────────────────────────
   Bootstrap's own .text-muted is not retuned to --brand-text-muted anywhere else in this file (a prior fix's
   own comment, below at .app-card > .card-header .card-subtitle, said so directly) — a bare .text-muted leaks
   an off-brand grey wherever it's used. One global override here fixes every existing instance at once
   (AddressBook.razor, Estimates.razor, ProductDetail.razor, OrdersHistory.razor, OrderDetails.razor,
   DefaultAddressSummaryCard.razor) rather than a per-file chase, and keeps the next screen that reaches for
   the familiar Bootstrap class from reintroducing the same drift. */
.text-muted {
    color: var(--brand-text-muted) !important;
}

/* ── Page header panel (.page-header) ──────────────────────────────────────────────────────────────────────
   RULED 2026-09-02 (Brian): the page header is HOST-OWNED vocabulary. A page whose header row carries
   right-hand content (a view switch, a primary action, a filter, a status badge/link) wraps that row in
   .page-header and the Shell paints it — the Project Management (Home) gradient panel at working-screen
   padding. Title left, right-hand content right. Modules adopt THIS name (Brian: "the Blicks should have
   classes that will have the same styling as the host application"); the Shell never targets a module's
   own wrapper class for this, except the two compiled packages documented in theme.css.
   CLASS NAMING RULED 2026-09-02 (Brian): "don't need to add app-, just do card-header ... try to overwrite
   standard classes and elements, unless overwriting is absolutely not possible" — the same ruling applies
   here, so this is `.page-header`, not the earlier `.app-page-header`; no invented prefix.
   The <h1> inside takes its size/weight/colour from `.content h1` (app.css) — nothing here restyles it.
   Pages with a title and no right-hand content do NOT use this class: they are a bare <h1> (T2). */
.page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--brand-space-4);
    background: linear-gradient(135deg, var(--brand-primary-lighter) 0%, var(--brand-primary-light) 100%);
    border: 1px solid var(--brand-primary-light);
    border-radius: var(--brand-radius-lg);
    padding: var(--brand-space-6);
    margin-bottom: var(--brand-space-4);
}
.page-header h1 { margin-bottom: 0; }

/* ── Breadcrumb (.app-breadcrumb) ─────────────────────────────────────────────────────────────────────────
   Brian, 2026-08-19: a breadcrumb belongs on an INDIVIDUAL RECORD page (a quote, a customer, a work order, a
   kit), never on a section landing screen — those carry a plain <h1> plus one .app-controls row and nothing
   else. The parent crumb is a LINK back to that record's list, so the trail replaces the older ad hoc
   "← Back to X" link rather than sitting above a second copy of it.
   Shell-owned and global because Blicks render this as plain markup: a Blick loads in its own
   AssemblyLoadContext and cannot reference CCP.Shell's Breadcrumb.razor, but Shell CSS still reaches its DOM
   (same precedent as .app-tabstrip above). */
.app-breadcrumb {
    margin-bottom: var(--brand-space-2);
}

.app-breadcrumb ol {
    display: flex;
    align-items: center;
    gap: var(--brand-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--brand-font-size-sm);
    color: var(--brand-text-muted);
}

.app-breadcrumb li + li::before {
    content: "/";
    margin-right: var(--brand-space-2);
    color: var(--brand-text-muted);
}

/* Brian, 2026-09-02, correcting his own 2026-09-02 rest-state change (reference:
   backlog/reference/aisv2/aisv2-customer-detail-alerts-and-breadcrumb.png — Home > Customers > 1000 BELMONT,
   ancestor crumbs muted grey, the current screen in the primary colour): the CURRENT screen's crumb is the one
   that carries --brand-primary, never an ancestor. A parent crumb is a real link back to the list, muted at
   rest — hover/focus is what reveals it as clickable, not its resting colour. */
.app-breadcrumb a {
    color: var(--brand-text-muted);
    text-decoration: none;
}

.app-breadcrumb a:hover,
.app-breadcrumb a:focus-visible {
    color: var(--brand-text);
    text-decoration: underline;
}

.app-breadcrumb a:focus-visible {
    box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--brand-primary) 25%, transparent);
    border-radius: var(--brand-radius-sm);
}

.app-breadcrumb li[aria-current="page"] {
    color: var(--brand-primary);
    font-weight: var(--brand-font-weight-medium);
}

/* ── Detail-screen carpet (.app-card) ────────────────────────────────────────────────────────────────────
   Detail-screen pattern (DESIGN-SYSTEM-DETAIL-SCREENS.md §1, Duane, 2026-09-01): the reference's two rounded
   white "carpets" on the grey page background -- the record card (header + info panels) and the tab card
   (strip + active panel). New Shell-owned class, joins the published app-* class contract (card #231 rider 2).
   Each screen stacks its own carpets in document order, so a flat margin-bottom (not a container gap) is
   enough to space consecutive cards -- the trailing margin on a page's last card costs nothing. */
.app-card {
    background: var(--brand-surface);
    border: 1px solid var(--brand-border);
    border-radius: var(--brand-radius-lg);
    box-shadow: var(--brand-shadow-sm);
    padding: var(--brand-space-5);
    margin-bottom: var(--brand-space-5);
}

/* Detail-screen info panels inside carpet 1 (DESIGN-SYSTEM-DETAIL-SCREENS.md §1): columns separated by hairline
   rules, not boxes -- the carpet is the box. Column count comes from the markup (grid-auto-flow: column), so one
   rule serves a three-column and a four-column screen alike. */
.app-panels {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: fit-content(20rem);
    justify-content: start;
    gap: var(--brand-space-5);
}

.app-panel { min-width: 12rem; }

.app-panels > * + * {
    border-left: 1px solid var(--brand-border);
    padding-left: var(--brand-space-5);
}

.app-panel-stack {
    display: flex;
    flex-direction: column;
    gap: var(--brand-space-5);
}

.app-panel-stack > .app-panel + .app-panel {
    border-top: 1px solid var(--brand-border);
    padding-top: var(--brand-space-5);
}

/* Two classes deep on purpose: app.css loads after this file, and its `.content h2` (one class) would otherwise
   win on order and paint the panel heading at --brand-font-size-lg. */
.app-panels .app-panel h2 {
    font-size: var(--brand-font-size-base);
    font-weight: var(--brand-font-weight-semibold);
    margin: 0 0 var(--brand-space-3);
}

.app-panels .app-panel h2 i {
    color: inherit;
    margin-right: var(--brand-space-2);
}

@media (max-width: 1080px) {
    .app-panels {
        grid-auto-flow: row;
        grid-template-columns: repeat(2, fit-content(20rem));
    }

    .app-panels > :nth-child(2n+1) {
        border-left: none;
        padding-left: 0;
    }

    .app-panels > :nth-child(n+3) {
        border-top: 1px solid var(--brand-border);
        padding-top: var(--brand-space-5);
    }
}

@media (max-width: 640px) {
    .app-panels { grid-template-columns: minmax(0, 1fr); }

    .app-panels > * + * {
        border-left: none;
        padding-left: 0;
        border-top: 1px solid var(--brand-border);
        padding-top: var(--brand-space-5);
    }
}

/* ── Order Totals carpet modifier (.app-card--order-totals) ──────────────────────────────────────────────
   L-254/L-258 (Order Details, 01-address-book-shipment-tracking.draft.md OH.2 B14): the one dark-navy carpet in
   the portal (shipped.png / in-production.png). Both declarations are brand tokens, never a raw literal --
   --brand-order-totals-bg is brand.css's alias of --brand-secondary (DESIGN-SYSTEM-EXTERNAL-SURFACES.md §3);
   --brand-text-on-brand (#FFFFFF) is the white text colour the card needs, so no new token was
   added for it. A modifier on .app-card, not a standalone class, so it keeps every other .app-card rule
   (radius, shadow, padding, spacing) and repaints only background/text. */
.app-card--order-totals {
    background: var(--brand-order-totals-bg);
    color: var(--brand-text-on-brand);
}

/* L-258: shared-readonly.css colours every .app-field-list dt / dd itself, which beats the colour inherited from
   the card; this higher-specificity rule puts the ledger back on the on-brand white. */
.app-card--order-totals .app-field-list dt,
.app-card--order-totals .app-field-list dd {
    color: var(--brand-text-on-brand);
}

/* ── Carpet-1 header row (.card-header, scoped to .app-card) ─────────────────────────────────────────────────
   CLASS NAMING RULED 2026-09-02 (Brian): "don't need to add app-, just do card-header ... try to overwrite
   standard classes and elements, unless overwriting is absolutely not possible." Bootstrap defines .card-header;
   the detail-screen header row is the same kind of thing, so it takes the same standard name instead of a new
   invented one. Scoped to .app-card rather than left bare, because a bare .card-header would also repaint every
   other Bootstrap card header in the app (KPI/admin cards) with a treatment sized for a record-detail title --
   the intent here is specifically the header row inside carpet 1 (DESIGN-SYSTEM-DETAIL-SCREENS.md §4).
   CustomerProfile.razor is the exemplar (Brian, T3 ruling 2026-09-02); QuoteDetails and VendorDetails converge
   onto this one rule instead of each carrying its own byte-identical .cp-header/.qw-header layout copy (a Blick
   still can't reference a sibling Blick's stylesheet, BD-BLOCK-PACKAGING-1, so each module keeps its own class
   alongside this one purely as a hook for its own inner structure -- .cp-header-info, .qw-header-title, etc.).
   The <h1> inside takes its size/weight/colour from .content h1 (app.css) -- nothing here restyles it.
   Carrie + Arthur, page-header gate 2026-09-02, FAIL 3: this rule and app.css's `.card > .card-header` are BOTH
   `.card-header` -- the same element matches both if it sits inside BOTH an `.app-card` and a genuine `.card`,
   and until this fix a header inside only `.app-card` still inherited Bootstrap's OWN `.card-header` declarations
   (padding, background-color, border-bottom, top-corner radius, all resolving against `--bs-card-*` custom
   properties that fall back to real values once ANY selector matches, not just when nested in `.card`) plus
   app.css's brand-token override (background/font-weight/color), since neither this rule's seven declarations
   nor anything else reset them: a --brand-surface-page-bg strip appeared inside the white .app-card, the title
   sat 16px further in (Bootstrap's own left/right padding survived; only padding-bottom was overridden here),
   and font-weight:semibold + color:navy were inherited by every child with no weight/colour of its own
   (.cp-header-address, .cp-header-phone). The four declarations below explicitly zero all of it -- this is now
   the ONLY source of paint for a carpet-1 header row; nothing rides in from either .card-header ancestor rule. */
.app-card > .card-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--brand-space-4);
    margin-bottom: var(--brand-space-4);
    border-bottom: 1px solid var(--brand-border);
    padding: 0 0 var(--brand-space-4);
    background: none;
    color: inherit;
    border-radius: 0;
}

/* VendorDetails.razor's own carpet-1 header row: CustomerProfile.razor's richer header (address/phone segments,
   badges) is CCP.CustomerContext.Blick's own markup inside .cp-header-info and stays there; VendorDetails has
   none of that content to show (it lives inside BD.VendorContext.Blick's VendorForm, out of the Shell's reach --
   DESIGN-SYSTEM-DETAIL-SCREENS.md §5 boundary note), so only the muted subtitle role needs a rule here.
   Renamed from the invented .app-card-header-subtitle to Bootstrap's own .card-subtitle (naming ruling above) --
   Bootstrap's default subtitle rule only sets a small negative top margin for stacking under a .card-title, which
   this override replaces with a flat 0 (this subtitle sits beside the <h1> as a flex sibling, not stacked under
   one) plus the brand's muted colour, since Bootstrap's own .text-muted is not retuned to --brand-text-muted
   (theme.css) and a bare Bootstrap class would leak an off-brand grey.
   Scoped to .app-card > .card-header, same reasoning and same blast-radius fix as .card-header two rules above
   (Carrie's 2026-09-02 review finding): a bare .card-subtitle would zero the margin on every Bootstrap card
   subtitle in the application, not just the one carpet-1 header row that has any today. */
.app-card > .card-header .card-subtitle {
    margin: 0;
    color: var(--brand-text-muted);
}

/* ── Tab-panel header row (.app-tabpanel-header) ──────────────────────────────────────────────────────────
   L-99 (Will, 2026-09-11/12): a TabStrip's active panel sometimes needs its own title + action row (e.g. an
   "Export to CSV" button beside the panel's own heading), but that row is a GRANDCHILD of the .app-card that
   hosts the TabStrip (it sits inside the tabpanel div), not a direct child -- so .app-card > .card-header
   above never reaches it, and the row rendered unstyled: no flex, no right-aligned button, no hairline. This
   is the same flex/space-between/hairline treatment as a carpet-1 .card-header, under its own name so it
   does not depend on being a direct .app-card child. */
.app-tabpanel-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--brand-space-4);
    margin-bottom: var(--brand-space-4);
    border-bottom: 1px solid var(--brand-border);
    padding: 0 0 var(--brand-space-4);
}

