/* TheraCALC | layout.css | v1.2 | 2026-07-22 | + shared text tokens --tc-hint/--tc-hint-size (§3c):
   helper/hint text under input labels, defined once (settings-token naming). #3d566e on white = 7.6:1
   (AA); consumed by acid-base .fh only (no other page shifts). Part of the --tc-* family Task D extends.
   | v1.1 | 2026-07-22 | + .tab--std shared tab surface (Phase 3 Task B):
   the unified INACTIVE tab treatment (#dde6f0 fill / #b4c4d8 border / #8aaabf edge+shadow) that AG's
   drug row and anticoag's module row already shared, now defined ONCE; AG's mode row adopts it
   (ending its #c8d8e8/#9ab0c8/#6a8aaa divergence). ACTIVE states stay page-local (theme.js remaps
   them per page). Vanco + opioid tabs are DIFFERENT designs by decision (opioid pill tabs kept per
   its v7.5 note) — not adopters. | v1.0 | 2026-07-22 | SHARED LAYOUT LAYER (structural phase, Phase 2).
   One authoritative home for layout primitives that used to live as private per-page copies —
   the way theracalc-nav.css already unifies navigation. GUARDED: hooks/pre-push fails any page
   whose inline <style> redefines a primitive owned here (re-divergence guard).

   OWNERSHIP MAP (what lives here vs. what stays page-local):
     HERE: scroll-gutter policy · tier width modifiers (.wrap--*) · canonical .row2 input grid ·
           the two-pane app shell (.layout/.lp/.rp + sticky, currently used by acid-base only).
     PAGE-LOCAL (deliberate, do NOT "harmonize"): per-page .wrap padding + overflow —
           BL-015: AG/anticoag .wrap{overflow-x:hidden} vs vanco .wrap{overflow-x:clip} vs
           acid-base .wrap{NO overflow — overflow-x on .wrap would force overflow-y:auto,
           creating a scroll container and BREAKING the sticky left panel (verified 2026-07-21)}.
           Also page-local: .step (a HOMONYM — 3 unrelated meanings on acid-base / pulse /
           opioid; never shareable), and page-specific shells (renal's .left-panel/.right-panel
           grid) pending their own adoption rounds. */

/* ── 1. GLOBAL SCROLL POLICY (site-wide decision, A3) ──────────────────────────
   Reserve the vertical-scrollbar gutter permanently so centered content doesn't recenter
   ("tab shift") when the page scrollbar appears/disappears across states. Visible only with
   classic scrollbars (e.g. Windows); macOS overlay scrollbars have zero layout width.
   Promoted from acid-base's page-local rule (v2.8) to the shared layer — every page linking
   this file inherits it, killing the shift class site-wide. */
html{scrollbar-gutter:stable}
@supports not (scrollbar-gutter:stable){ html{overflow-y:scroll} }

/* ── 2. TIER WIDTH MODIFIERS (additive; measured, not guessed) ─────────────────
   Pages ADD one of these classes to their existing wrapper element and drop the private
   max-width/margin pair. Class names are ADDITIVE modifiers — existing class names are never
   renamed (JS selectors + jsHash must keep working; invariance recorded constraint A1).
   Assignments (Phase 1 measurements 2026-07-22):
     form 680    → aminoglycoside · anticoag · opioid (all panes fit 680 fully expanded)
     content 900 → resources
     article 1080→ the-pulse hub (pulse newsletters are 1000 page-local — documented residual)
     app 1400    → vancomycin · acid-base · renal (two-pane calculators) */
.wrap--form{max-width:680px;margin-left:auto;margin-right:auto}
.wrap--content{max-width:900px;margin-left:auto;margin-right:auto}
.wrap--article{max-width:1080px;margin-left:auto;margin-right:auto}
.wrap--app{max-width:1400px;margin-left:auto;margin-right:auto}

/* ── 3. CANONICAL INPUT GRID ───────────────────────────────────────────────────
   minmax(0,1fr) NOT 1fr: 1fr means minmax(auto,1fr) — a long label (e.g. LACTATE's reference
   text) can push its column past the even split and clip the neighbor. minmax(0,1fr) keeps the
   split even regardless of content (the lactate-clip fix, now the shared default so that bug
   class is extinct, not fixed-on-one-page). */
.row2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:4px}

/* ── 3b. SHARED TAB SURFACE (.tab--std, additive modifier — Task B) ────────────
   The unified INACTIVE tab treatment. Adopters keep page-local: radius, padding, font sizing,
   width, and ALL active-state rules (theme.js remaps actives per page). `.tab` itself is a
   3-page homonym (AG/vanco/opioid) and is never claimed here. */
.tab--std{background:#dde6f0;color:var(--navy);border:1.5px solid #b4c4d8;border-bottom:3px solid #8aaabf;
  box-shadow:0 2px 0 #8aaabf,0 3px 8px rgba(20,50,100,.10);cursor:pointer;text-transform:uppercase;
  font-weight:800;transition:all .12s;-webkit-tap-highlight-color:transparent}
.tab--std:active{transform:translateY(1px);box-shadow:0 1px 0 #8aaabf}

/* ── 3c. SHARED TEXT TOKENS ────────────────────────────────────────────────────
   --tc-hint / --tc-hint-size: helper/hint text under input labels (settings-page-style token
   naming). #3d566e on white = 7.6:1 (WCAG AA needs 4.5:1 — the acid-base hint it replaces was
   8.5px #2874A6 ≈ 4.9:1, passing on colour but illegibly small). Part of the --tc-* family the
   Task D Windows-token proposal extends; consume via var() with a fallback. Currently consumed
   by acid-base's .fh only — adopting elsewhere is per-page, reported, never a silent restyle. */
:root{--tc-hint:#3d566e;--tc-hint-size:10.5px}

/* ── 3d. TASK D — Windows contrast tokens (BL-019; signed selected approach + measured caption). ───────────
   The A-split: DECORATIVE edges (card borders, dividers, table rules) take --tc-line; CONTROL
   boundaries (input/select/interactive-component borders) take --tc-line-control (3.13:1 on card #fff,
   meeting WCAG 1.4.11's 3:1). --tc-line-control-nocard is the fallback for a control that sits
   border-on-page-bg with no lighter fill (3.57:1 on --tc-bg). --tc-text-faint replaces the old #8a9bb0
   caption (2.84:1, FAILED AA) — measured 5.90 on card / 4.65 on --tc-bg / 5.90 white-on-badge.
   ⚠ COUPLING (BL-019 cond.1): --tc-text-faint 4.65 on --tc-bg clears AA by only 0.15 — if --tc-bg ever
   darkens, this text silently drops below AA. validation/tests/contrast.spec.js ENFORCES the ratios
   (asserts computed WCAG, not the hex) so a regression whichever token moves goes RED, not silent. */
:root{
  --tc-font-ui:-apple-system,BlinkMacSystemFont,"Segoe UI Variable Text","Segoe UI",Roboto,system-ui,sans-serif;
  --tc-bg:#dde5f0;
  --tc-card:#fff;
  --tc-line:#a4b8cc;              /* decorative edges (2.04:1 — 1.4.11 n/a to purely decorative) */
  --tc-line-control:#7d94ad;      /* input/select/control boundary — 3.13:1 on card */
  --tc-line-control-nocard:#647890; /* control border-on-page-bg fallback — 3.57:1 on --tc-bg */
  --tc-text-faint:#53667c;        /* faint caption — 5.90 card / 4.65 --tc-bg / 5.90 white-on-badge */
  --tc-card-shadow:0 1px 3px rgba(20,40,80,.14), 0 1px 2px rgba(20,40,80,.10);
}

/* ── 4. TWO-PANE APP SHELL (.layout / .lp / .rp) ───────────────────────────────
   Relocated VERBATIM from acid-base v2.12 (the hard-won sticky-left-panel model, Task C).
   Currently adopted by acid-base only; vars (--hh, --lw, --ab-sticky-offset) are defined by
   the adopting page. On pages that don't use these classes this block is inert. */
.layout{display:flex;height:calc(100vh - var(--hh))}
.lp{width:var(--lw);flex-shrink:0;background:var(--white);border-right:2px solid var(--bdr);display:flex;flex-direction:column;min-height:0;overflow-y:auto}
.rp{flex:1;min-width:0;overflow-y:auto;padding:14px 20px 60px;background:var(--bg)}
/* STICKY-LEFT-PANEL desktop layout. Natural page scroll: layout + panels are content-height
   (no stretch → no void below short results); the input panel sticks below the sticky stack.
   Offset derives from --ab-sticky-offset (single source on the page). Scoped ≥801px; below
   800 the page's stacked-layout media rules win. */
@media(min-width:801px){
  .layout{height:auto}
  .lp{position:sticky;top:var(--ab-sticky-offset);align-self:flex-start;height:auto;max-height:calc(100vh - var(--ab-sticky-offset));overflow-y:auto}
  .rp{align-self:flex-start;height:auto;overflow-y:visible}
  #results{scroll-margin-top:var(--ab-sticky-offset)}
  /* Collapse the empty-state holder once results render, so #results butts against the input
     panel instead of leaving a gap (.rp{flex:1 1 0%} otherwise grows to fill the leftover).
     .has-results is toggled by the page JS at the same two points that show/hide #results. */
  .layout.has-results .rp{display:none}
}
