/* ============================================================================
   ew-ui.css  --  EdWise UI SDK global stylesheet  (ships from Ew.Ui.Components)
   ----------------------------------------------------------------------------
   The GLOBAL (non-scoped) polish that makes raw Radzen widgets look like the
   EdWise design system out of the box. Component-specific styling lives in each
   component's scoped .razor.css (shipped automatically in <App>.styles.css);
   THIS file covers the widgets Radzen renders without a wrapping Ew component
   -- dialogs, tabs, the data-grid pager -- which the Material base leaves with
   raw browser chrome (boxy <button> tabs, bulleted pager lists, mismatched
   control sizes).

   Consumers reference it ONCE:
       <link rel="stylesheet" href="_content/Ew.Ui.Components/css/ew-ui.css" />
   placed AFTER the Radzen Material base theme and BEFORE app-specific overrides,
   so it overrides Radzen's defaults but an app can still override it.

   Everything here is TOKEN-DRIVEN with fallbacks: it adapts to whatever palette
   the app sets (--rz-primary, --rz-base-*, ...) and still looks right with no
   palette at all. A fix to any of these widgets is made HERE, once, and every
   consuming app picks it up -- nothing to copy per app.
   ============================================================================ */

/* --- Typography: the heading voice (EdWise theme, 2026-06-09 spec section 6) ------------
   Avenir Next (the brand face -- licensed webfonts, agency-delivered, self-hosted like
   RobotoFlex) carries headings, display styles, and KPI numbers; body/forms/grids stay
   Roboto Flex via the base's --rz-text-font-family. ONE family name with explicit weights
   so the bundled woff2s win consistently over any locally-installed desktop cuts (whose
   Medium registers as a separate family). Falls back to Roboto gracefully if the files
   are absent. Keep in sync: font files ship in ../fonts/ in the same package. */
@font-face {
    font-family: "Avenir Next";
    src: url("../fonts/AvenirNext-Regular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "Avenir Next";
    src: url("../fonts/AvenirNext-Medium.woff2") format("woff2");
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "Avenir Next";
    src: url("../fonts/AvenirNext-Bold.woff2") format("woff2");
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}
/* Material Symbols FOUT fix ------------------------------------------------
   The licensed base declares the "Material Symbols" face WITHOUT font-display
   (so the browser default `auto` applies). On a cold load that flashes the raw
   ligature TEXT of every Radzen icon -- "home", "expand_more", "chevron_left",
   "account_balance" -- until the ~1 MB icon woff2 finishes downloading.

   Re-declaring the SAME family to bolt font-display on is NOT reliable: when two
   @font-face rules share family/weight/style, browsers do not consistently take
   font-display from the later rule (Chrome commonly keeps the first-declared
   face, i.e. the base's `auto`). So instead we declare a DISTINCT family that
   only we own -- here font-display:block is unambiguously in force -- and
   repoint Radzen's icon-font token (`--rz-icon-font-family`, consumed by every
   `.rzi`) to it. `block` (not `swap`) keeps glyphs INVISIBLE during load instead
   of painting ligature names, then swaps in the real glyphs once loaded.

   `block` only hides for a ~3s block period, and in a Blazor WASM boot the 1 MB
   font can queue behind the _framework payload past that window -- so consumers
   MUST also add the icon-font <link rel="preload"> to their host index.html
   (see the SDK README "Icon font preload" note) to fetch it up front. */
@font-face {
    font-family: "Material Symbols Ew";
    src: url("../fonts/MaterialSymbolsOutlined.woff2") format("woff2 supports variations"),
         url("../fonts/MaterialSymbolsOutlined.woff2") format("woff2-variations");
    font-style: normal;
    font-weight: 100 700;
    font-display: block;
}
:root {
    /* Wins over the base token (ew-ui.css loads after material3-base.css). */
    --rz-icon-font-family: "Material Symbols Ew";
}

h1, h2, h3, h4, h5, h6,
.rz-text-h1, .rz-text-h2, .rz-text-h3, .rz-text-h4, .rz-text-h5, .rz-text-h6,
.rz-text-display-h1, .rz-text-display-h2, .rz-text-display-h3,
.rz-text-display-h4, .rz-text-display-h5, .rz-text-display-h6,
.ew-kpi-value, .ew-kpi-stat-value {
    font-family: var(--ew-heading-font-family, 'Avenir Next', Roboto, sans-serif);
}

/* --- Dialog surfaces ----------------------------------------------------- */
/* Pure white to match the dialog body (no titlebar/body seam). --rz-white is
   literally #ffffff in every palette; the fallback covers a missing token.
   .rz-dialog (CENTER dialogs) is included: the base paints it --rz-base-200,
   which is a gray seam against the white titlebar in light and inverts to an
   unusable mid-gray in dark (the dark layer re-points both to its elevated
   surface). */
.rz-dialog-titlebar,
.rz-dialog-side-titlebar {
    background-color: var(--rz-white, #ffffff);
}
.rz-dialog,
.rz-dialog-side {
    background-color: var(--rz-white, #ffffff);
}

/* --- Icon buttons (dialog close-X, dropdown clear-X) ---------------------
   The Material base leaves these with browser-default <button> chrome (gray
   box + outset border). Reset to clean, borderless icon buttons. */
.rz-dialog-titlebar-close,
.rz-dropdown-clear-icon {
    -webkit-appearance: none;
    appearance: none;
    border: none;
    background: transparent;
    box-shadow: none;
    color: var(--rz-text-secondary-color, #454a4f);
    cursor: pointer;
}
.rz-dialog-titlebar-close {
    width: 2rem;
    height: 2rem;
    padding: 0;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.15s, color 0.15s;
}
/* Hover brightens to the full text tone. (NOT base-900: that stays near-black in the dark
   ramp, which made the hovered X vanish on dark surfaces; text-color is the same #1b1d20
   in light and flips with the mode.) */
.rz-dialog-titlebar-close:hover {
    background: color-mix(in srgb, var(--rz-text-color, #1b1d20) 8%, transparent);
    color: var(--rz-text-color, #1b1d20);
}
.rz-dropdown-clear-icon:hover {
    color: var(--rz-text-color, #1b1d20);
    opacity: 1;
}

/* --- Dropdown filter search: clear-X + empty state -----------------------
   Radzen's single-select filter popup shows a search box but (1) no way to wipe the typed text
   and (2) a blank panel when the term matches nothing (its EmptyTemplate only covers a wholly
   empty data source, not a zero-match filter). Both are fixed here so every EwDropdown behaves
   the same with no markup change.

   Clear-X: the button is injected by js/ew-dropdown-filter.js. The filter container is a
   row-reverse flexbox (search icon on the left, input filling the rest), so the button is
   positioned absolutely on the RIGHT rather than fighting the flex order; it shows only while
   there is text, and the input reserves right padding so the two never overlap. Separate from
   AllowClear, which clears the selected value. */
.rz-dropdown-filter-container {
    position: relative;
}
.rz-dropdown-filter-container.ew-has-filter-text .rz-dropdown-filter {
    padding-right: 1.5rem;
}
.rz-dropdown-filter-container .ew-dropdown-filter-clear {
    position: absolute;
    top: 50%;
    right: 0.375rem;
    transform: translateY(-50%);
    display: none;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    padding: 0;
    border: 0;
    background: transparent;
    cursor: pointer;
    color: var(--rz-text-secondary-color, #454a4f);
    font-family: var(--rz-icon-font-family, "Material Symbols Ew");
    font-size: 1.125rem;
    line-height: 1;
    -webkit-font-feature-settings: "liga";
    font-feature-settings: "liga";
    -webkit-font-smoothing: antialiased;
}
.rz-dropdown-filter-container.ew-has-filter-text .ew-dropdown-filter-clear {
    display: inline-flex;
}
.rz-dropdown-filter-container .ew-dropdown-filter-clear:hover {
    color: var(--rz-text-color, #1b1d20);
}

/* Empty state: surface a message in the empty list (zero-match filter) and in the empty items
   wrapper (wholly empty data source), instead of a blank panel. Text is a CSS var so an app can
   localize it once globally. */
.rz-dropdown-panel .rz-dropdown-items:empty::after,
.rz-dropdown-panel .rz-dropdown-items-wrapper:empty::after {
    content: var(--ew-dropdown-empty-text, "No records to display.");
    display: block;
    padding: 0.5rem 0.75rem;
    color: var(--rz-text-tertiary-color, #6b7280);
    font-size: 0.8125rem;
}

/* --- Notification toast close-X (RadzenNotification) ---------------------
   The Material base leaves this as a raw <button> (gray box + outset border).
   Reset to a clean borderless icon that inherits the toast's own (light) text
   color, with a subtle white hover on the colored success/error/etc. toasts. */
.rz-notification-close {
    -webkit-appearance: none;
    appearance: none;
    border: none;
    background: transparent;
    box-shadow: none;
    color: inherit;
    opacity: 0.8;
    cursor: pointer;
    padding: 0;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: background-color 0.15s ease, opacity 0.15s ease;
}
.rz-notification-close:hover {
    opacity: 1;
    background: rgba(255, 255, 255, 0.18);
}

/* --- Tabs (RadzenTabs) ---------------------------------------------------
   Each tab is a <button> the base never resets, so it falls back to default
   button chrome (gray box). Reset it; render a clean underlined Material tab.
   The nav carries an inset baseline and the active tab an inset bottom
   indicator on the SAME plane (the active line replaces the baseline -- no
   double underline). Radzen's animated li::after indicator is disabled (it
   stacked with ours + left paint trails when clicking between tabs). */
.rz-tabview-nav {
    background: color-mix(in srgb, var(--rz-text-color, #1b1d20) 3%, transparent);
    box-shadow: inset 0 -1px 0 0 var(--rz-base-300, #dfe5ec);
    padding: 0 0.75rem;
    gap: 0.25rem;
}
.rz-tabview-nav li { margin: 0; }
.rz-tabview-nav li::after { display: none !important; }
.rz-tabview-nav li button {
    -webkit-appearance: none;
    appearance: none;
    padding: 0.875rem 1rem;
    font-family: inherit;
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--rz-text-secondary-color, #454a4f);
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: inset 0 -2px 0 0 transparent;
    cursor: pointer;
    transition: color 0.15s ease;
}
.rz-tabview-nav li button:hover { color: var(--rz-text-color, #1b1d20); }
.rz-tabview-nav li.rz-tabview-selected button {
    color: var(--rz-primary, #004af2);
    box-shadow: inset 0 -2px 0 0 var(--rz-primary, #004af2);
}
.rz-tabview-nav li button .rz-tabview-title {
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    color: inherit;
}

/* --- Pager (RadzenDataGrid / RadzenPager) --------------------------------
   Radzen ships the pager controls at mismatched sizes: 28px page/arrow buttons
   (compact grids) or 48px (default density) next to a 40px page-size dropdown,
   with different corner radii -- so the bar reads as a jumble. Pull every
   control into ONE coherent family (32px tall, 8px radius) and reset the stray
   <ul>/<li> bullets the base leaves on .rz-pager-pages.
   (.rz-pager-element is on EVERY pager button -- first/prev/page/next/last;
   .rz-pager-page is the numbered one; .rz-paginator-page is an older alias.) */
.rz-pager {
    display: flex;
    align-items: center;
    /* Text-wash, not base-200: the base ramp re-maps light under the dark theme (inversion trap). */
    border-top: 1px solid color-mix(in srgb, var(--rz-text-color, #1b1d20) 10%, transparent);
    padding: 0.625rem 1rem;
    font-size: 0.8125rem;
    gap: 0.5rem;
}

/* The pager nav is the grid's NEXT tab stop (tabindex=0, roving buttons inside at -1) but had
   no visible focus indicator -- keyboard focus appeared to vanish after the grid (WCAG 2.4.7). */
.rz-pager:focus-visible {
    outline: 2px solid var(--rz-primary, #004af2);
    outline-offset: -2px;
    border-radius: 4px;
}

/* Flat buttons: the M3 elevation-1 shadow on filled buttons (primary AND light/secondary) reads
   dated against the SDK's flat card language -- same ruling as EwSectionCard. Cover the state
   variants too so hover/active don't re-raise elevation. */
.rz-button.rz-variant-filled,
.rz-button.rz-variant-filled:hover,
.rz-button.rz-variant-filled:active,
.rz-button.rz-variant-filled:focus {
    box-shadow: none;
}

/* Boolean controls: Radzen renders these as ARIA widgets (div role=checkbox/radio/switch with
   tabindex=0; the native input is hidden at -1). Space toggles per the APG pattern, but the
   base ships NO visible focus indicator (WCAG 2.4.7). */
.rz-chkbox:focus-visible .rz-chkbox-box {
    outline: 2px solid var(--rz-primary, #004af2);
    outline-offset: 2px;
}
.rz-radiobutton:focus-visible .rz-radiobutton-box {
    outline: 2px solid var(--rz-primary, #004af2);
    outline-offset: 2px;
}
.rz-switch:focus-visible {
    outline: 2px solid var(--rz-primary, #004af2);
    outline-offset: 2px;
    border-radius: 12px;
}
.rz-pager-pages,
.rz-pager .rz-pager-item {
    list-style: none;
    margin: 0;
    display: inline-flex;
    align-items: center;
}
.rz-pager-pages { gap: 2px; }

/* every pager button -- one size + shape. Radzen sizes these via
   min-height/line-height/padding (NOT an explicit height), and its compact
   selector (.rz-pager.rz-density-compact .rz-pager-element) out-specifies a
   plain .rz-pager rule -- so match BOTH densities and override min-height, or
   the buttons stay 48px / 28px and clash with the 32px dropdown. */
.rz-pager .rz-pager-element,
.rz-pager.rz-density-compact .rz-pager-element,
.rz-pager .rz-paginator-page {
    min-width: 32px;
    min-height: 32px;
    height: 32px;
    padding: 0 6px;
    line-height: 1;
    border-radius: 50%;   /* circular page/arrow buttons (matches the original Radzen pager) -- 32x32 = circle */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--rz-text-color, #1b1d20);
    transition: background-color 0.15s ease, color 0.15s ease;
}
.rz-pager .rz-pager-element:not(.rz-state-active):not(.rz-state-disabled):hover,
.rz-pager .rz-paginator-page:not(.rz-state-active):not(.rz-state-disabled):hover {
    background-color: color-mix(in srgb, var(--rz-text-color, #1b1d20) 8%, transparent);
}
.rz-pager .rz-pager-element.rz-state-disabled {
    opacity: 0.38;
    cursor: default;
}
.rz-pager .rz-pager-page.rz-state-active,
.rz-pager .rz-paginator-page.rz-state-active {
    background-color: var(--rz-primary-lighter, rgba(0, 74, 242, 0.12));
    font-weight: 600;
}

/* page-size dropdown -- shrink from Radzen's 40px input height to the buttons'
   32px + match the radius. */
.rz-pager .rz-dropdown {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 32px;
    min-height: 32px;
    min-width: 70px;
    border-radius: 8px;
    /* Radzen ships 7px vertical padding here, which shrinks the content box below the 24px label height
       -- so align-items can't vertically center the value (it sits off-center). Kill the vertical
       padding (keep horizontal). */
    padding: 0 0.5rem;
}
.rz-pager .rz-dropdown .rz-dropdown-trigger { height: 32px; display: flex; align-items: center; }
/* The value label is a DIRECT child of .rz-dropdown (the trigger only holds the caret). Make it fill the
   full height + tightly center its own text, with no vertical padding/line-height nudging the number. */
.rz-pager .rz-dropdown-label {
    display: flex;
    align-items: center;
    height: 32px;
    line-height: 1;
    padding-top: 0;
    padding-bottom: 0;
    margin: 0;
    text-overflow: clip;
    overflow: visible;
}

/* summary + "items per page" -- muted, same compact size as the controls */
.rz-pager .rz-pager-summary,
.rz-pager .rz-pagesize-text {
    color: var(--rz-text-secondary-color, #454a4f);
}

/* EwPageHeader: the title <h1> is a PROGRAMMATIC focus target (Blazor <FocusOnNavigate Selector="h1"/>
   for screen-reader heading focus) -- not keyboard-tabbable, so its focus ring is just an ugly box on
   every navigation. Suppress it. No-op for apps that don't use FocusOnNavigate. */
.ew-page-header h1:focus,
.ew-page-header h1:focus-visible {
    outline: none;
}

/* --- Buttons: the M3 emphasis ladder (EdWise theme, 2026-06-09 spec section 5) ---------
   The licensed base styles Variant.Flat as just "Filled minus shadow" -- the SDK had no real
   medium emphasis. Restyle Flat as M3 filled-tonal: container fill + on-container label, no
   elevation. Primary/Secondary tonal-ize on SECONDARY-container (not primary-container: on
   dark, a T30 primary container out-shouts the pale T80 filled primary and inverts the
   hierarchy); severity buttons tonal-ize with their own family container. Hover/press/focus
   ride the ink/white scrim tokens declared in material3-base-overrides / dark-overrides. */
.rz-button.rz-primary.rz-variant-flat,
.rz-button.rz-secondary.rz-variant-flat {
    background-color: var(--rz-secondary-light, #dfe1f9);
    color: var(--rz-on-secondary-light, #171b2c);
}
.rz-button.rz-success.rz-variant-flat {
    background-color: var(--rz-success-light, #a0f6ae);
    color: var(--rz-on-success-light, #00210a);
}
.rz-button.rz-warning.rz-variant-flat {
    background-color: var(--rz-warning-light, #ffdeae);
    color: var(--rz-on-warning-light, #281900);
}
.rz-button.rz-danger.rz-variant-flat {
    background-color: var(--rz-danger-light, #ffdad6);
    color: var(--rz-on-danger-light, #410002);
}
.rz-button.rz-info.rz-variant-flat {
    background-color: var(--rz-info-light, #b9eaff);
    color: var(--rz-on-info-light, #001f29);
}
.rz-button.rz-light.rz-variant-flat {
    background-color: color-mix(in srgb, var(--rz-text-color, #1b1d20) 10%, transparent);
    color: var(--rz-base-900, #1b1d20);
}

/* Neutral (Light) FILLED buttons: M3 has no "gray filled" role -- the washed gray pill reads
   cheap next to a filled primary (user call, 2026-06-10). Neutral high-emphasis renders as the
   M3 outlined quiet button instead: transparent fill, outline-role border, body label. The
   gray tonal remains available as Neutral + Variant.Flat. */
.rz-button.rz-light.rz-variant-filled {
    background-color: transparent;
    border: 1px solid var(--ew-button-outline, #74797e);
    /* Body label via the theme-aware text token (was --rz-base-900, which inverts to the dark
       canvas color in dark mode -> dark-on-dark). --rz-text-color is #1b1d20 light / #e0e4e9 dark. */
    color: var(--rz-text-color, #1b1d20);
}

/* Outlined buttons: border upgrades from the faint input gray (base-600, ~1.5:1 on white) to
   the M3 OUTLINE role via --ew-button-outline (base-700 light; dark-overrides points it at the
   dark outline equivalent) -- a control boundary should clear ~3:1. Labels keep their family
   color from the base theme. */
.rz-button.rz-variant-outlined.rz-primary,
.rz-button.rz-variant-outlined.rz-secondary,
.rz-button.rz-variant-outlined.rz-success,
.rz-button.rz-variant-outlined.rz-warning,
.rz-button.rz-variant-outlined.rz-danger,
.rz-button.rz-variant-outlined.rz-info,
.rz-button.rz-variant-outlined.rz-light {
    border-color: var(--ew-button-outline, #74797e);
}

/* Center dialogs must stack ABOVE side sheets. Radzen 10.2.1 gives both stacks z-index 1001,
   so a confirm opened FROM a side-sheet form (the EdWise pattern: form in a side sheet,
   Delete/Override confirms as center dialogs) can render underneath the sheet wherever they
   overlap -- the confirm's buttons become unclickable at narrow viewports. Found by MASTERed's
   E2E dialog round-trip suite. Toasts (rz-notification, 1010+) stay above both. */
.rz-dialog-wrapper {
    z-index: 1002;
}
