/* ============================================================
   FSH DESIGN TOKENS — the single authoritative token layer.
   Loaded immediately after MudBlazor.min.css and before every
   project stylesheet (see clients' index.html).

   Project stylesheets load AFTER this file, so they win on
   source order at equal specificity. That means: to change a
   token here, change it here. Do NOT re-declare spacing,
   radius, or shadow literals in a project stylesheet — the
   `audit-design-tokens.sh` gate rejects that.

   ── Layout guarantee: chrome must never scroll the document ──
   Off-canvas chrome (the ThemeDrawer, the AI-notification drawer) is
   parked outside the viewport. MudBlazor ships
   `.mud-drawer:not(.mud-drawer-fixed) { position: absolute }`, and a
   closed right-anchored temporary drawer therefore lands at
   left:360px / right:740px on a 360px viewport. Because its offset
   parent `.mud-layout` is position:relative and so in flow, that
   drawer establishes DOCUMENT horizontal overflow — measured
   documentElement.scrollWidth 740 against a 360px viewport, so every
   page scrolled sideways.

   `overflow-x: clip` is the fix, and `clip` rather than `hidden`
   deliberately: `hidden` turns the root into a scroll container and
   breaks `position: sticky` descendants, whereas `clip` clips without
   creating a scrollport. `overflow-x: clip` is also compatible with
   `overflow-y: visible`, so vertical scrolling is untouched.

   This does NOT clip legitimate wide content: tables scroll inside
   `.mud-table-container { overflow-x: auto }`, which is the behaviour
   that must be preserved.

   Ownership:
     spacing  --space-1..8   4px base; --space-3 is THE region gap
     surface  --surface-0..3 tonal ladder (light + dark)
     radius   --radius-sm..full, each with a stated purpose
     shadow   --shadow-1..4  INTERACTION ONLY (hover/drag/overlay)
     type     --text-micro..display, mapped once onto MudBlazor

   Consumers: Fsh.Blazor.Components (EntityTable, KpiCard,
   PageHeader) plus every client (Vallecer, Dakak, Zaneco,
   Playground) via _content/Fsh.Blazor.Components/tokens.css.
   ============================================================ */

:root {
    /* Chrome must never establish horizontal document overflow. See the header
       comment for the measurement (documentElement.scrollWidth 740 on a 360px
       viewport, caused by an off-canvas drawer at position:absolute) and for why
       `clip` is used instead of `hidden`. */
    overflow-x: clip;
}

/* ── FOCUS VISIBLE ────────────────────────────────────────────────────────
   MudBlazor ships two unconditional resets in MudBlazor.min.css:

       button:focus { outline: none }
       input:focus  { outline: none }

   Those sit at specificity (0,1,1) and therefore outrank a bare
   `:focus-visible` rule at (0,1,0) — so the project's correct ring in
   fsh.css never took effect anywhere in the product. Verified with CDP
   CSS.getMatchedStylesForNode on .td-close-btn, cascade order:

       3  :focus-visible   outline: 2px solid var(--mud-palette-primary)   <- ours, loses
       4  button:focus     outline: none                                    <- MudBlazor, wins

   Measured impact: 7 of 8 tabbable ThemeDrawer controls matched
   :focus-visible and rendered no indicator at all — a WCAG 2.4.7 failure
   app-wide.

   The fix restores the ring at matching specificity. It needs NO !important
   because this file loads immediately after MudBlazor.min.css, so at equal
   specificity source order decides in our favour, and the design-token
   !important budget stays untouched.

   `:focus-visible` rather than `:focus` is deliberate: the library's reset
   was presumably trying to suppress the ring on mouse click, which
   :focus-visible does natively and correctly. Keying on :focus instead
   would put a ring on every click. */
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
a:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* ── CLOSED DRAWERS MUST NOT BE TAB-STOPPERS ──────────────────────────────
   MudBlazor parks a closed drawer off-canvas and intends to take it out of
   the render tree: it ships

       .mud-drawer--initial { display: none }
       .mud-drawer.mud-drawer-responsive.mud-drawer-<breakpoint>
           .mud-drawer--initial:not(.mud-drawer-mini) { display: none !important }

   Neither takes effect here. Measured with CDP getMatchedStylesForNode on the
   drawer: the ONLY rule matching `display` was MudBlazor's own
   `.mud-drawer { display: flex }`, and the computed result was
   `display: flex; visibility: visible; left: -240px` — i.e. rendered, on
   screen nowhere, and still focusable.

   Consequence, measured: the closed nav drawer reports **359 focusable
   elements**. Pressing Tab on any page walks the user through 359 off-screen
   navigation links, and the closed ThemeDrawer's controls come next. Keyboard
   users are trapped in a UI they cannot see, and with the focus-ring fix each
   of those stops now paints a ring around an invisible control.

   The rule below mirrors MudBlazor's own intent, scoped to the two overlay variants
   (`.mud-drawer-temporary` and `.mud-drawer-responsive`) so a persistent drawer that
   relies on a slide transition is untouched.

   Scoped by variant, NOT by `--initial`: scoping to `--initial` was the first attempt
   and it silently stopped working after the drawer's first open, because MudBlazor drops
   `--initial` once a drawer has been seen. Verified — with the `--initial` version, the
   drawer computed `display: none` before it had ever been opened, but `display: flex`
   again after one open/close cycle, and its controls rejoined the tab order.

   `display: none` is safe for these two variants because MudBlazor's slide transition is
   scoped to `.mud-drawer-persistent`, which this rule does not match. `:not(.mud-drawer-mini)`
   preserves the mini/rail variant, which must stay visible when collapsed. */
.mud-drawer.mud-drawer--closed.mud-drawer-temporary:not(.mud-drawer-mini),
.mud-drawer.mud-drawer--closed.mud-drawer-responsive:not(.mud-drawer-mini) {
    display: none;
}

:root {
    /* ── SPACING RHYTHM ──────────────────────────────────
       4px base. Two anchors carry the whole system:
         --space-2   8px  gap between elements in ONE region (cluster)
         --space-3  12px  gap between page REGIONS
       Naming the anchors is what makes the audit gate a grep.

       WHY 12px AND NOT 24PX. Measured across the repo before choosing:
       744 razor files use `mb-3` and NOTHING else for region spacing,
       vs ~217 that are mixed and ~217 that use only `mb-4`. The app's
       de-facto convention is therefore 12px, so 12px is the canonical
       region gap and this migration is a consistency fix rather than a
       silent loosening of three quarters of the UI. --space-5 (24px)
       stays available for deliberate major section breaks. */
    --space-1:   4px;  /* icon <-> label, hairline offsets            */
    --space-2:   8px;  /* button row gap, chip padding-y            */
    --space-3:  12px;  /* REGION GAP - card <-> card, block <-> block */
    --space-4:  16px;  /* card padding, table cell-x                 */
    --space-5:  24px;  /* MAJOR section break (deliberate, not default) */
    --space-6:  32px;  /* page header <-> first block                */
    --space-8:  48px;  /* major group separation                     */

    /* Legacy aliases. premium.css already declares --cell-padding-*
       and --nav-padding-*; these keep those call sites working while
       pointing at the rhythm. Declared here so the values have ONE
       definition and premium.css only references them.
       NOTE: --cell-padding-y was 10px in premium.css, which is
       off-rhythm. Snapped to --space-2 (8px), a deliberate ~2px
       tightening of table row density, consistent with the compact
       table density this system standardises on. */
    --cell-padding-x: var(--space-4);
    --cell-padding-y: var(--space-2);
    --nav-padding-x:  var(--space-4);
    --nav-padding-y:  var(--space-2);

    /* ── SURFACE LADDER (tonal elevation) ───────────────────
       Structure is expressed by LIGHTNESS + a hairline border, not
       by a resting shadow. See --shadow-* below for interaction. */
    --surface-0: #ffffff;  /* page background                        */
    --surface-1: #fbfcfd;  /* card                                   */
    --surface-2: #f4f6f9;  /* inset, toolbar, table head, nav rail   */
    --surface-3: #eaeef4;  /* hover wash                             */
    --line:        #e3e8ef;
    --line-strong: #d3dae4;

    /* ── SHADOW LADDER — INTERACTION ONLY ───────────────────
       Never use these to show structure. Allowed only on
       :hover, :active, drag, and overlay states.

       Alpha scales with --fsh-elevation, which BaseLayout emits
       from ClientPreference.Elevation (MudBlazor's MudTheme has no
       elevation slot, so the slider would otherwise be inert).
       Default elevation 1 reproduces the base values exactly; higher
       settings deepen interaction depth without adding any resting
       shadow, so structural separation stays purely tonal. */
    --shadow-alpha: calc(var(--fsh-elevation, 1) * 0.05);

    --shadow-1: 0 1px 2px rgba(16, 24, 40, var(--shadow-alpha));                        /* hover    */
    --shadow-2: 0 2px 8px rgba(16, 24, 40, calc(var(--shadow-alpha) * 1.4)),
                0 1px 2px rgba(16, 24, 40, var(--shadow-alpha));                         /* raised   */
    --shadow-3: 0 8px 24px rgba(16, 24, 40, calc(var(--shadow-alpha) * 2));              /* drag     */
    --shadow-4: 0 20px 48px rgba(16, 24, 40, calc(var(--shadow-alpha) * 3.2));           /* overlay  */

    /* ── RADIUS LADDER ───────────────────────────────────────
       Purpose per step; do not use a step outside its purpose.
       The ladder is a RATIO of --radius-unit so the whole set
       tracks the user's border-radius preference. MudBlazor emits
       --mud-default-borderradius from ClientPreference.BorderRadius
       (default 5px), which yields 5 / 8 / 12 / 16 at the default
       and scales proportionally at every other setting. Setting the
       preference to 0 therefore sharpens every radius at once. */
    --radius-unit: var(--mud-default-borderradius, 5px);
    --radius-sm:   var(--radius-unit);                 /* 5px  inputs, buttons, chips, nav links */
    --radius-md:   calc(var(--radius-unit) * 1.6);     /* 8px  cards, dropdowns, table shells    */
    --radius-lg:   calc(var(--radius-unit) * 2.4);     /* 12px dialogs, hero panels              */
    --radius-xl:   calc(var(--radius-unit) * 3.2);     /* 16px modals, marketing surfaces        */
    --radius-full: 999px;                              /* avatars, status dots, pills           */

    /* ── TYPE SCALE ──────────────────────────────────────────
       Define the size ONCE, then reference the step. Components
       must not declare their own font-size literals. */
    --text-micro:   .6875rem;  /* 11px uppercase labels, chips    */
    --text-caption: .75rem;    /* 12px secondary/meta              */
    --text-body:    .8125rem;  /* 13px UI default, table cells     */
    --text-sm:      .875rem;   /* 14px                             */
    --text-title:   1.25rem;   /* 20px section titles              */
    --text-display: 1.75rem;   /* 28px page titles                 */
    --text-page:    2rem;      /* 32px legacy H3, avoid in new work */

    /* ── MOTION ────────────────────────────────────────────── */
    --motion-duration-fast:   150ms;
    --motion-duration-normal: 300ms;
    --motion-duration-slow:   500ms;
    --motion-ease:      cubic-bezier(0.4, 0, 0.2, 1);
    --motion-ease-out:  cubic-bezier(0, 0, 0.2, 1);
}

/* ── DARK THEME ──────────────────────────────────────────
   Every ladder is redefined here, adjacent to the light block
   above, so a missing dark value is a one-screen diff rather
   than a hunt. The ladder INVERTS rather than reusing hues. */
.dark-theme {
    --surface-0: #0d0f12;
    --surface-1: #14171c;
    --surface-2: #1b1f26;
    --surface-3: #232833;
    --line:        #262b34;
    --line-strong: #333a45;

    /* Dark mode already needs more opacity for the same perceived depth,
       so it starts higher (0.40 at elevation 1) and scales on the same
       --fsh-elevation factor. */
    --shadow-alpha-dark: calc(0.30 + var(--fsh-elevation, 1) * 0.10);
    --shadow-1: 0 1px 2px rgba(0, 0, 0, var(--shadow-alpha-dark));
    --shadow-2: 0 2px 8px rgba(0, 0, 0, var(--shadow-alpha-dark));
    --shadow-3: 0 8px 24px rgba(0, 0, 0, calc(var(--shadow-alpha-dark) * 1.35));
    --shadow-4: 0 20px 48px rgba(0, 0, 0, calc(var(--shadow-alpha-dark) * 1.6));
}

/* MudBlazor emits --mud-typography-*-size from the active theme.
   Mapping it here means ONE place governs base type size instead
   of premium.css re-declaring 0.8125rem on ~10 selectors. */
:root {
    --mud-typography-body1-size: var(--text-sm);
    --mud-typography-body2-size: var(--text-body);
    --mud-typography-default-size: var(--text-body);
    --mud-typography-button-size: var(--text-body);
    --mud-typography-caption-size: var(--text-caption);
    --mud-typography-subtitle1-size: var(--text-sm);
    --mud-typography-subtitle2-size: var(--text-body);
}

/* ── SEMANTIC LAYOUT CLASSES ─────────────────────────────────
   The sanctioned way to space page regions. New pages use these
   instead of per-page margin/padding utility classes. Each class states its
   own gap, so a page's rhythm is readable from its class list. */

.fsh-page {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* The card owns its own bottom margin so markup does not have to say
   `Class="fsh-card mb-4"`. MudBlazor's spacing utilities are all
   `!important` (.mb-4 { margin-bottom: 16px !important }), so they cannot be
   overridden from here — they must be removed from the markup instead.

   --space-4 is 16px, which is exactly what `.mb-4` resolved to, so folding
   the utility into this class is a pixel-identical refactor. Do not "tidy" this
   to --space-3: the region gap is for blocks, and cards currently sit at 16px.
   Changing that is a design decision, not a cleanup. */
.fsh-card {
    background: var(--surface-1);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    margin-bottom: var(--space-4);
}

/* Flush cards are edge-to-edge (table/media wrappers), so they opt out of both
   padding and the bottom margin. */
.fsh-card--flush {
    background: var(--surface-1);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 0;
    margin-bottom: var(--space-4);
    overflow: hidden;
}

.fsh-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.fsh-cluster {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.fsh-kpi {
    background: var(--surface-1);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    transition: box-shadow var(--motion-duration-fast) var(--motion-ease),
                border-color var(--motion-duration-fast) var(--motion-ease);
}

/* Interaction is the only sanctioned shadow on a static surface. */
.fsh-kpi:hover {
    box-shadow: var(--shadow-2);
    border-color: var(--line-strong);
}

@media (max-width: 600px) {
    .fsh-page,
    .fsh-section {
        gap: var(--space-2);
    }
}

@media (prefers-reduced-motion: no-preference) {
    .fsh-card,
    .fsh-kpi {
        transition-duration: var(--motion-duration-fast);
    }
}

/* ── EntityTable: advanced-search panel ─────────────────────────
   Replaces inline Style="padding:5px!important; margin-bottom:10px
   !important; border-radius:…" on MudExpansionPanel. The old values
   were literals; the region gap is now --space-3 and the radius comes
   from the ladder, so the panel participates in the rhythm. */
.fsh-advanced-search {
    padding: var(--space-1) !important;
    margin-bottom: var(--space-5) !important;
    border-radius: var(--radius-md) !important;
    background: var(--surface-1);
    border: 1px solid var(--line);
}

/* Replaces inline Style="flex:none!important;margin:0px!important" on the
   search field so it can shrink inside the panel without an override. */
.fsh-advanced-search-field {
    flex: none !important;
    margin: 0 !important;
}

/* Replaces inline style="margin-top:10px!important" on the all-columns
   toggle row — a cluster gap, so --space-3 rather than a literal. */
.fsh-advanced-search-toggles {
    margin-top: var(--space-3) !important;
    padding: var(--space-2);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
