/* GENERATED by the BundleSiteCss MSBuild target (build/BundleSiteCss.targets) from site.css — do not edit, do not commit. */
/* ==========================================================================
   Lisbon Modern Theme — entry point
   This file aggregates the modular token files under ./tokens/. Order is
   significant: _base sets every legacy token, additive files extend the
   system, and _dark sits last so its [data-theme="dark"] overrides win.

   See ./tokens/CHANGELOG.md for the token system changelog and
   /docs/design-system/SOP-claude-design-to-blazor.md for the workflow.

   Delivery: Development serves this file (live-editable @imports). All other
   environments serve css/site.bundle.css — a git-ignored single file that the
   BundleSiteCss MSBuild target (AL.Web.csproj) regenerates from this chain on
   every build. Adding/reordering an @import here is all that's needed.
   ========================================================================== */


/* ── inlined: tokens/_base.css ── */
/* ==========================================================================
   Lisbon Modern — Base tokens (light theme)
   The original Lisbon Modern theme. Values are unchanged from the pre-split
   site.css so that no existing page renders differently.
   ========================================================================== */

:root {
    /* Brand colours */
    --color-primary:        #0D3B66;   /* navy */
    --color-primary-light:  #154D80;   /* lighter navy for hover states */
    --color-primary-dark:   #092A4A;   /* darker navy for active states */
    --color-secondary:      #4A90D9;   /* azulejo blue */
    --color-secondary-light:#6BA3E0;
    /* Completes the light/base/dark triad --color-primary already has. Exists because
       --color-secondary as TEXT on --color-surface-alt is only 2.97:1 (WCAG AA needs 4.5:1);
       this is 4.82:1 on that background. Use it for secondary-coloured TEXT on tinted
       surfaces; keep --color-secondary for fills, accents, badges and focus rings. */
    --color-secondary-dark: #2B6CB0;
    --color-accent:         #F4D35E;   /* tram yellow */
    --color-accent-dark:    #D4B43E;

    /* Surfaces */
    --color-background:     #FFFFFF;
    --color-surface:        #F8F9FA;
    --color-surface-alt:    #EEF2F7;

    /* Text */
    --color-text:           #1A1A2E;
    --color-text-muted:     #5A6270;
    --color-text-on-primary:#FFFFFF;
    --color-text-on-accent: #1A1A2E;

    /* Borders */
    --color-border:         #D6DCE5;
    --color-border-light:   #E8ECF1;

    /* Feedback */
    --color-success:        #26B050;
    --color-danger:         #DC3545;
    --color-warning:        #FFC107;

    /* Text-safe siblings of the feedback hues, matching --color-secondary-dark (ds-v1.1.6).
       The base hues are tuned as FILLS; as TEXT on our light surfaces they miss WCAG AA —
       --color-success 2.69:1 where large text needs 3, --color-danger 4.30:1 where normal
       text needs 4.5. Borders and fills keep the base hue. */
    --color-success-dark:   #23A54B;
    --color-danger-dark:    #D53342;
    --color-info:           var(--color-secondary);

    /* Sidebar */
    --sidebar-bg:           linear-gradient(180deg, var(--color-primary) 0%, var(--color-primary-dark) 100%);
    --sidebar-text:         #D7D7D7;
    --sidebar-active-bg:    rgba(255, 255, 255, 0.18);
    --sidebar-hover-bg:     rgba(255, 255, 255, 0.10);
    --sidebar-brand-color:  #FFFFFF;

    /* Top bar */
    --topbar-bg:            var(--color-surface-alt);
    --topbar-border:        var(--color-border);

    /* Typography (legacy — new code should prefer the scale in _type.css) */
    --font-family-base:     'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif;
    --font-size-base:       1rem;
    --line-height-base:     1.6;

    /* Spacing (legacy — new code should prefer the fluid --space-* in _space.css) */
    --spacing-xs:           0.25rem;
    --spacing-sm:           0.5rem;
    --spacing-md:           1rem;
    --spacing-lg:           1.5rem;
    --spacing-xl:           2rem;

    /* Border radius */
    --radius-sm:            0.25rem;
    --radius-md:            0.375rem;
    --radius-lg:            0.5rem;

    /* Shadows (legacy — new code should prefer --elevation-* in _elevation.css) */
    --shadow-sm:            0 1px 3px rgba(13, 59, 102, 0.08);
    --shadow-md:            0 4px 12px rgba(13, 59, 102, 0.10);
    --shadow-lg:            0 8px 24px rgba(13, 59, 102, 0.12);

    /* Transitions (legacy — new code should prefer --duration-* + --ease-* in _motion.css) */
    --transition-fast:      150ms ease-in-out;
    --transition-base:      250ms ease-in-out;

    /* ── ds-v1.1.0 additions ─────────────────────────────────────── */
    /* Sidebar width — central source-of-truth referenced by the .page
       CSS-grid template-columns in MainLayout. Changing this token here
       slides the whole app shell. */
    --sidebar-width:           240px;

    /* Landing page dark-mode token. Describes the DARK variant explicitly,
       so it is declared here on :root and the consuming CSS rules guard
       themselves with [data-theme="dark"] selectors. It IS also re-declared
       in _dark.css — that came from the ds-v1.1.1 sweep that re-declared the
       derived tokens under [data-theme="dark"] (CSS resolves a custom
       property's var() at the DECLARING element, so :root-only derived
       tokens kept their light literals in dark mode). This particular token
       is a literal gradient with no var(), so the re-declaration is
       redundant rather than load-bearing — keep the two in sync if either
       changes. (--landing-nav-* removed in ds-v1.1.9 with the
       .landing-nav → .marketing-nav unification.) */
    --landing-hero-bg-dark:    linear-gradient(180deg, #0D3B66 0%, #092A4A 100%);

    /* Section eyebrow accent — same yellow in both themes; references
       --color-accent which is identical light & dark. */
    --landing-eyebrow-color:   var(--color-accent);

    /* Expanded-row detail pane tokens. The accent token references
       --color-secondary so it lifts in dark mode automatically. */
    --detail-pane-accent:      var(--color-secondary);
    --detail-pane-bg:          var(--color-surface);
    --detail-pane-padding:     var(--space-lg);

    /* ── ds-v1.1.1 additions ─────────────────────────────────────── */
    /* Vertical offset of the icon centre on a .how-it-works-step card.
       The azulejo connector line on .how-it-works::before sits at this
       offset and runs horizontally through the icon row. */
    --how-it-works-icon-centre: 6.5rem;
}


/* ── inlined: tokens/_type.css ── */
/* ==========================================================================
   Type scale — fluid via clamp()
   Each token interpolates between a phone-portrait minimum and a desktop
   maximum based on viewport width. The middle term controls the curve.
   Values targeted assuming a 360 → 1920 px viewport interpolation range
   (clamp() handles clamping outside that range automatically).
   ========================================================================== */

:root {
    /* Font sizes (fluid) */
    --text-xs:      clamp(0.75rem,  0.71rem + 0.18vw, 0.875rem);   /* 12 → 14 */
    --text-sm:      clamp(0.875rem, 0.83rem + 0.20vw, 1rem);       /* 14 → 16 */
    --text-base:    clamp(1rem,     0.95rem + 0.22vw, 1.125rem);   /* 16 → 18 */
    --text-lg:      clamp(1.125rem, 1.06rem + 0.30vw, 1.3125rem);  /* 18 → 21 */
    --text-xl:      clamp(1.25rem,  1.16rem + 0.42vw, 1.5rem);     /* 20 → 24 */
    --text-2xl:     clamp(1.5rem,   1.36rem + 0.65vw, 1.875rem);   /* 24 → 30 */
    --text-3xl:     clamp(1.875rem, 1.66rem + 0.95vw, 2.5rem);     /* 30 → 40 */
    --text-4xl:     clamp(2.25rem,  1.86rem + 1.74vw, 3.5rem);     /* 36 → 56 */
    --text-display: clamp(2.75rem,  2.05rem + 3.10vw, 5rem);       /* 44 → 80 */

    /* Line heights */
    --leading-tight:    1.15;
    --leading-snug:     1.30;
    --leading-normal:   1.50;
    --leading-relaxed:  1.70;

    /* Font weights */
    --font-regular:  400;
    --font-medium:   500;
    --font-semibold: 600;
    --font-bold:     700;

    /* Letter spacing */
    --tracking-tight:  -0.01em;
    --tracking-normal: 0;
    --tracking-wide:   0.02em;
    --tracking-wider:  0.05em;
}


/* ── inlined: tokens/_space.css ── */
/* ==========================================================================
   Fluid spacing scale
   --space-* tokens scale with viewport via clamp(): tight on phones, generous
   on ultrawide. Existing --spacing-* tokens in _base.css remain fixed for
   backward compatibility — new code should prefer --space-*.
   ========================================================================== */

:root {
    --space-3xs: clamp(0.125rem, 0.10rem + 0.10vw, 0.1875rem);  /* 2 → 3 */
    --space-2xs: clamp(0.25rem,  0.21rem + 0.15vw, 0.375rem);   /* 4 → 6 */
    --space-xs:  clamp(0.375rem, 0.32rem + 0.22vw, 0.5rem);     /* 6 → 8 */
    --space-sm:  clamp(0.5rem,   0.43rem + 0.30vw, 0.75rem);    /* 8 → 12 */
    --space-md:  clamp(0.75rem,  0.65rem + 0.45vw, 1.125rem);   /* 12 → 18 */
    --space-lg:  clamp(1rem,     0.85rem + 0.65vw, 1.5rem);     /* 16 → 24 */
    --space-xl:  clamp(1.5rem,   1.25rem + 1.10vw, 2.25rem);    /* 24 → 36 */
    --space-2xl: clamp(2rem,     1.65rem + 1.55vw, 3rem);       /* 32 → 48 */
    --space-3xl: clamp(3rem,     2.45rem + 2.40vw, 4.5rem);     /* 48 → 72 */
    --space-4xl: clamp(4rem,     3.20rem + 3.50vw, 6.5rem);     /* 64 → 104 */
}


/* ── inlined: tokens/_elevation.css ── */
/* ==========================================================================
   Elevation ladder (e0..e5)
   Layered box-shadows scaled for perceived depth. Two-layer shadows
   (close + far) give a softer, more natural look than single-layer.
   Dark-mode overrides switch the rgba base from navy to black.
   ========================================================================== */

:root {
    --elevation-0: none;
    --elevation-1: 0 1px 2px rgba(13, 59, 102, 0.06),
                   0 1px 3px rgba(13, 59, 102, 0.08);
    --elevation-2: 0 2px 4px rgba(13, 59, 102, 0.07),
                   0 4px 8px rgba(13, 59, 102, 0.09);
    --elevation-3: 0 4px 8px rgba(13, 59, 102, 0.08),
                   0 8px 16px rgba(13, 59, 102, 0.10);
    --elevation-4: 0 8px 16px rgba(13, 59, 102, 0.10),
                   0 16px 32px rgba(13, 59, 102, 0.12);
    --elevation-5: 0 16px 32px rgba(13, 59, 102, 0.12),
                   0 32px 64px rgba(13, 59, 102, 0.14);
}

[data-theme="dark"] {
    --elevation-1: 0 1px 2px rgba(0, 0, 0, 0.30),
                   0 1px 3px rgba(0, 0, 0, 0.40);
    --elevation-2: 0 2px 4px rgba(0, 0, 0, 0.40),
                   0 4px 8px rgba(0, 0, 0, 0.50);
    --elevation-3: 0 4px 8px rgba(0, 0, 0, 0.50),
                   0 8px 16px rgba(0, 0, 0, 0.60);
    --elevation-4: 0 8px 16px rgba(0, 0, 0, 0.60),
                   0 16px 32px rgba(0, 0, 0, 0.70);
    --elevation-5: 0 16px 32px rgba(0, 0, 0, 0.70),
                   0 32px 64px rgba(0, 0, 0, 0.80);
}


/* ── inlined: tokens/_motion.css ── */
/* ==========================================================================
   Motion tokens
   Durations and easings for transitions/animations across the app.
   Global reduced-motion override neutralises animation everywhere components
   reference these tokens.
   ========================================================================== */

:root {
    /* Durations */
    --duration-instant:     0ms;
    --duration-fast:        150ms;
    --duration-base:        250ms;
    --duration-slow:        400ms;
    --duration-slower:      600ms;
    --duration-reveal:      700ms;

    /* Easings */
    --ease-linear:          linear;
    --ease-out:             cubic-bezier(0.16, 1, 0.3, 1);     /* gentle deceleration — UI default */
    --ease-in:              cubic-bezier(0.7, 0, 0.84, 0);     /* sharp acceleration — for exits */
    --ease-in-out:          cubic-bezier(0.65, 0, 0.35, 1);    /* balanced — for cross-fades */
    --ease-spring:          cubic-bezier(0.5, 1.6, 0.4, 0.7);  /* slight overshoot */
}

/* Reduced-motion preference: collapse durations and short-circuit any
   animation/transition. Components that reference --duration-* get this
   for free; the universal *,*::before,*::after rule catches anything else. */
@media (prefers-reduced-motion: reduce) {
    :root {
        --duration-instant: 0ms;
        --duration-fast:    0ms;
        --duration-base:    0ms;
        --duration-slow:    0ms;
        --duration-slower:  0ms;
        --duration-reveal:  0ms;
    }

    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}


/* ── inlined: tokens/_state.css ── */
/* ==========================================================================
   Semantic state tokens
   For status badges, alerts, roadmap items. Each state ships three values:
     --state-{name}      strong accent (icons, dots, borders)
     --state-{name}-bg   soft background tint (badge fill)
     --state-{name}-fg   foreground colour for use on the -bg
   Dark-mode overrides flip the -bg/-fg pair while keeping the accent legible.
   ========================================================================== */

:root {
    /* Live / shipped */
    --state-live:           #26B050;
    --state-live-bg:        #DBF1E2;
    --state-live-fg:        #155724;

    /* Beta / preview */
    --state-beta:           #4A90D9;
    --state-beta-bg:        #DFEDF9;
    --state-beta-fg:        #0E3A5F;

    /* Planned / coming soon */
    --state-planned:        #8B96A8;
    --state-planned-bg:     #EDEFF3;
    --state-planned-fg:     #3B4351;

    /* Deprecated / sunset */
    --state-deprecated:     #B5774B;
    --state-deprecated-bg:  #F3E4D6;
    --state-deprecated-fg:  #5B3A1F;

    /* Touch target minimum (used by interactive primitives on phones) */
    --touch-target-min:     44px;
}

[data-theme="dark"] {
    --state-live:           #4ECF73;
    --state-live-bg:        #143820;
    --state-live-fg:        #6FE291;

    --state-beta:           #6BA3E0;
    --state-beta-bg:        #102740;
    --state-beta-fg:        #8BC1F2;

    --state-planned:        #A5B0C2;
    --state-planned-bg:     #1F2A38;
    --state-planned-fg:     #B0BAC9;

    --state-deprecated:     #C99268;
    --state-deprecated-bg:  #3B2615;
    --state-deprecated-fg:  #DFB585;
}


/* ── inlined: tokens/_breakpoints.css ── */
/* ==========================================================================
   Responsive breakpoint and container tokens
   CSS @media rules cannot reference custom properties directly. These tokens
   exist for documentation, JS, and container-query base widths. When writing
   media queries, repeat the numeric literal AND annotate with the token name
   in a trailing inline comment, e.g.
       @media (min-width: 900px) { ... }   [matches --bp-md]
   ========================================================================== */

:root {
    /* Viewport breakpoints */
    --bp-sm:   600px;
    --bp-md:   900px;
    --bp-lg:   1280px;
    --bp-xl:   1600px;
    --bp-2xl:  1920px;
    --bp-3xl:  2560px;

    /* Container max-widths */
    --container-narrow:   1100px;
    --container-default:  1400px;
    --container-app:      1600px;
}


/* ── inlined: tokens/_dark.css ── */
/* ==========================================================================
   Dark mode overrides
   Applied when [data-theme="dark"] is set on an ancestor element.
   js/theme.js sets it on <html> (the ThemeToggle button only carries the
   [data-theme-toggle] hook it listens for); the /design/tokens preview page can also
   set it on a local wrapper to scope dark mode to that page only.
   ========================================================================== */

[data-theme="dark"] {
    /* Brand colours — lifted toward lighter values so they read on dark surfaces. */
    --color-primary:         #5BA0E8;
    --color-primary-light:   #7DB5EF;
    --color-primary-dark:    #4A8FD8;
    --color-secondary:       #6BA3E0;
    --color-secondary-light: #8FBCEC;
    /* In dark mode the contrast problem inverts: --color-surface-alt is #1E2937, so the
       already-lifted --color-secondary is high-contrast as text. Alias rather than darken —
       a literal dark blue here would be unreadable on the dark topbar. */
    --color-secondary-dark:  var(--color-secondary);
    --color-accent:          #F4D35E;
    --color-accent-dark:     #D4B43E;

    /* Surfaces — dark navy base, tinted steps for layering. */
    --color-background:      #0E1620;
    --color-surface:         #161F2C;
    --color-surface-alt:     #1E2937;

    /* Text */
    --color-text:            #E8ECF1;
    --color-text-muted:      #9AA5B5;
    --color-text-on-primary: #0E1620;   /* dark text on lightened primary */
    --color-text-on-accent:  #1A1A2E;

    /* Bootstrap's secondary text (.form-text, .text-body-secondary, disabled nav/page links).
       We theme with data-theme, not data-bs-theme, so Bootstrap never swaps this to its dark
       value: its light rgba(33, 37, 41, 0.75) measured 1.05:1 on --color-surface. */
    --bs-secondary-color:    var(--color-text-muted);

    /* Borders */
    --color-border:          #2A3645;
    --color-border-light:    #1F2A38;

    /* Feedback — slightly lifted for legibility on dark. */
    --color-success:         #4ECF73;
    --color-danger:          #EF6171;

    /* Dark surfaces already pass, so these collapse to the base hues. */
    --color-success-dark:    var(--color-success);
    --color-danger-dark:     var(--color-danger);
    --color-warning:         #FFD740;

    /* Sidebar — pushed darker than surfaces so it still feels "deep". */
    --sidebar-bg:            linear-gradient(180deg, #0A1018 0%, #050810 100%);
    --sidebar-text:          #C8D0DC;
    --sidebar-active-bg:     rgba(255, 255, 255, 0.10);
    --sidebar-hover-bg:      rgba(255, 255, 255, 0.06);
    --sidebar-brand-color:   #FFFFFF;

    /* Top bar */
    --topbar-bg:             var(--color-surface);
    --topbar-border:         var(--color-border);

    /* Shadows — black-based so they read on dark surfaces. */
    --shadow-sm:             0 1px 3px rgba(0, 0, 0, 0.40);
    --shadow-md:             0 4px 12px rgba(0, 0, 0, 0.50);
    --shadow-lg:             0 8px 24px rgba(0, 0, 0, 0.60);

    /* ── Re-declare ds-v1.1.0 derived tokens under dark theme ─────────
       The tokens in _base.css are declared with var() references like
       `--detail-pane-bg: var(--color-surface)`. CSS resolves a custom-
       property's var() at the DECLARING element, then the LITERAL
       inherits down — it does NOT re-substitute per descendant. So in
       dark mode the light-theme literal sticks unless we re-declare
       here against the dark --color-* values.
       Status SIBA port (May 2026) surfaced this bug. */
    --landing-hero-bg-dark:    linear-gradient(180deg, #0D3B66 0%, #092A4A 100%);
    --landing-eyebrow-color:   var(--color-accent);
    --detail-pane-accent:      var(--color-secondary);
    --detail-pane-bg:          var(--color-surface);
    --detail-pane-padding:     var(--space-lg);
}

/* Bootstrap utility class overrides for dark mode.
   Many existing pages use Bootstrap's bg-light / bg-warning / text-muted
   without going through the token system. Without these overrides those
   classes produce stark white / yellow patches on dark backgrounds, killing
   readability. Each override aims to preserve the SEMANTIC of the class
   while picking a value that reads on dark.
   The selectors all start with [data-theme="dark"] so light mode is unaffected. */
[data-theme="dark"] .text-muted {
    color: var(--color-text-muted) !important;
}

[data-theme="dark"] .bg-light,
[data-theme="dark"] .bg-white {
    background-color: var(--color-surface) !important;
    color: var(--color-text);
}

[data-theme="dark"] .bg-warning.bg-opacity-25,
[data-theme="dark"] .bg-warning.bg-opacity-10 {
    background-color: color-mix(in srgb, var(--color-warning) 14%, transparent) !important;
}

[data-theme="dark"] .bg-info.bg-opacity-25,
[data-theme="dark"] .bg-info.bg-opacity-10 {
    background-color: color-mix(in srgb, var(--color-info) 14%, transparent) !important;
}

[data-theme="dark"] .bg-success.bg-opacity-25,
[data-theme="dark"] .bg-success.bg-opacity-10 {
    background-color: color-mix(in srgb, var(--color-success) 14%, transparent) !important;
}

[data-theme="dark"] .bg-danger.bg-opacity-25,
[data-theme="dark"] .bg-danger.bg-opacity-10 {
    background-color: color-mix(in srgb, var(--color-danger) 14%, transparent) !important;
}

/* Bootstrap alert variants (.alert-info / .alert-warning / .alert-success /
   .alert-danger) moved to wwwroot/css/bootstrap-dark.css per brief §6.3. */

/* Bootstrap table-light / table-striped variants — they hard-code Bootstrap
   greys that look stark on dark. Map to our surface token. */
[data-theme="dark"] .table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--color-text);
    --bs-table-striped-bg: var(--color-surface);
    --bs-table-striped-color: var(--color-text);
    --bs-table-border-color: var(--color-border-light);
    --bs-table-hover-bg: var(--color-surface-alt);
    --bs-table-hover-color: var(--color-text);
}

[data-theme="dark"] .table-light,
[data-theme="dark"] .table-light > th,
[data-theme="dark"] .table-light > td {
    --bs-table-bg: var(--color-surface-alt);
    --bs-table-color: var(--color-text);
    color: var(--color-text);
}

/* Bootstrap .card / .card-header chrome moved to wwwroot/css/bootstrap-dark.css
   per brief §6.3. Same for .form-control / .form-select (base + placeholder +
   focus) — see that file for the consolidated rules. */

/* Bootstrap close button (btn-close) is a hard-coded dark SVG — invisible on dark.
   Use the white variant. */
[data-theme="dark"] .btn-close {
    filter: invert(1) grayscale(100%) brightness(200%);
}

/* Modal overlay — preserve readability of the underlying dark background. */
[data-theme="dark"] .modal-content {
    background-color: var(--color-surface);
    color: var(--color-text);
    border-color: var(--color-border-light);
}

[data-theme="dark"] .modal-header,
[data-theme="dark"] .modal-footer {
    border-color: var(--color-border-light);
}

/* Bootstrap dropdown menu */
[data-theme="dark"] .dropdown-menu {
    background-color: var(--color-surface);
    color: var(--color-text);
    border-color: var(--color-border-light);
    box-shadow: var(--elevation-3);
}

[data-theme="dark"] .dropdown-item {
    color: var(--color-text);
}

[data-theme="dark"] .dropdown-item:hover,
[data-theme="dark"] .dropdown-item:focus {
    background-color: var(--color-surface-alt);
    color: var(--color-text);
}

/* Late-bound !important overrides for .alert-success/.alert-danger removed:
   bootstrap-dark.css's [data-theme="dark"] .alert-X (specificity 0,2,0)
   already beats app.css's bare .alert-X (0,1,0) without !important. */


/* Primitives — global stylesheets for components whose styles must cross
   scope boundaries (e.g. Reveal staggers descendants in consumer scope). */

/* ── inlined: primitives/reveal.css ── */
/* ==========================================================================
   Reveal primitive — scroll-fade-in
   Global stylesheet because stagger children rendered by consuming components
   sit in a different scope from Reveal itself.

   Reveal is implemented via a one-shot CSS animation (not a transition) so
   it doesn't interfere with the host element's own :hover / focus transitions
   after the reveal completes. Stagger uses an inline --reveal-delay custom
   property set by reveal.js.
   ========================================================================== */

.reveal[data-reveal="hidden"],
[data-reveal-child][data-reveal="hidden"] {
    opacity: 0;
    will-change: opacity, transform;
}

/* Variants — apply translation offset only while hidden. */
.reveal--fade-up[data-reveal="hidden"],
[data-reveal-child][data-reveal="hidden"] {
    transform: translateY(24px);
}

.reveal--fade-down[data-reveal="hidden"]  { transform: translateY(-24px); }
.reveal--fade-left[data-reveal="hidden"]  { transform: translateX(24px); }
.reveal--fade-right[data-reveal="hidden"] { transform: translateX(-24px); }
.reveal--fade-in[data-reveal="hidden"]    { transform: none; }

/* When marked visible, run a one-shot animation back to identity. */
.reveal[data-reveal="visible"],
[data-reveal-child][data-reveal="visible"] {
    opacity: 1;
    transform: none;
    animation: reveal-in var(--duration-reveal) var(--ease-out) var(--reveal-delay, 0ms) both;
}

.reveal--fade-up[data-reveal="visible"],
[data-reveal-child][data-reveal="visible"] {
    animation-name: reveal-fade-up;
}

.reveal--fade-down[data-reveal="visible"]  { animation-name: reveal-fade-down; }
.reveal--fade-left[data-reveal="visible"]  { animation-name: reveal-fade-left; }
.reveal--fade-right[data-reveal="visible"] { animation-name: reveal-fade-right; }
.reveal--fade-in[data-reveal="visible"]    { animation-name: reveal-fade-in; }

@keyframes reveal-fade-up {
    from { opacity: 0; transform: translateY(24px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes reveal-fade-down {
    from { opacity: 0; transform: translateY(-24px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes reveal-fade-left {
    from { opacity: 0; transform: translateX(24px); }
    to   { opacity: 1; transform: translateX(0); }
}
@keyframes reveal-fade-right {
    from { opacity: 0; transform: translateX(-24px); }
    to   { opacity: 1; transform: translateX(0); }
}
@keyframes reveal-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* Reduced-motion: show immediately, no animation. */
@media (prefers-reduced-motion: reduce) {
    .reveal[data-reveal="hidden"],
    [data-reveal-child][data-reveal="hidden"],
    .reveal[data-reveal="visible"],
    [data-reveal-child][data-reveal="visible"] {
        opacity: 1 !important;
        transform: none !important;
        animation: none !important;
    }
}


/* ── inlined: primitives/bottom-sheet.css ── */
/* ==========================================================================
   BottomSheet primitive
   Phone-portrait: slides up from bottom (bottom sheet).
   Tablet+: centered card (regular modal).
   Global stylesheet because the panel may host content from any consumer scope.
   ========================================================================== */

.bottom-sheet {
    position: fixed;
    inset: 0;
    z-index: 1500;
    pointer-events: none;
    visibility: hidden;
}

.bottom-sheet.is-open {
    pointer-events: auto;
    visibility: visible;
}

.bottom-sheet-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(13, 22, 32, 0.55);
    opacity: 0;
    transition: opacity var(--duration-base) var(--ease-out);
}

.bottom-sheet.is-open .bottom-sheet-backdrop {
    opacity: 1;
}

.bottom-sheet-panel {
    position: absolute;
    background: var(--color-background);
    color: var(--color-text);
    box-shadow: var(--elevation-4);
    display: flex;
    flex-direction: column;
    transition: transform var(--duration-base) var(--ease-out);

    /* Phone-portrait defaults: bottom sheet */
    left: 0;
    right: 0;
    bottom: 0;
    max-height: 90vh;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    transform: translateY(100%);
    padding-bottom: env(safe-area-inset-bottom, 0);
}

.bottom-sheet.is-open .bottom-sheet-panel {
    transform: translateY(0);
}

/* Tablet+: centered modal card */
@media (min-width: 600px) {  /* --bp-sm */
    .bottom-sheet-panel {
        left: 50%;
        right: auto;
        bottom: auto;
        top: 50%;
        width: min(560px, calc(100vw - 2 * var(--space-xl)));
        max-height: 80vh;
        border-radius: var(--radius-lg);
        transform: translate(-50%, calc(-50% + 20px));
        padding-bottom: 0;
    }

    .bottom-sheet.is-open .bottom-sheet-panel {
        transform: translate(-50%, -50%);
    }
}

.bottom-sheet-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    padding: var(--space-md) var(--space-lg);
    border-bottom: 1px solid var(--color-border-light);
}

.bottom-sheet-title {
    font-size: var(--text-lg);
    color: var(--color-primary);
    margin: 0;
    font-weight: var(--font-semibold);
}

.bottom-sheet-close {
    background: transparent;
    border: 0;
    color: var(--color-text-muted);
    padding: var(--space-2xs);
    cursor: pointer;
    border-radius: var(--radius-sm);
    min-width: var(--touch-target-min);
    min-height: var(--touch-target-min);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.bottom-sheet-close:hover {
    background: var(--color-surface-alt);
    color: var(--color-text);
}

.bottom-sheet-body {
    padding: var(--space-lg);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}


/* ── inlined: primitives/responsive-table.css ── */
/* ==========================================================================
   ResponsiveTable primitive
   Container-query driven: <table> at wide, card list at narrow. Both layouts
   live in the DOM; CSS toggles which is visible based on container width.
   Global stylesheet because the rendered cells/cards are in consumer scope.
   ========================================================================== */

.responsive-table {
    container-type: inline-size;
    width: 100%;
}

.responsive-table-table {
    width: 100%;
    border-collapse: collapse;
    color: var(--color-text);
}

.responsive-table-table thead th {
    text-align: left;
    padding: var(--space-sm) var(--space-md);
    background: var(--color-surface-alt);
    color: var(--color-primary);
    font-weight: var(--font-semibold);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    border-bottom: 2px solid var(--color-primary);
    white-space: nowrap;
}

.responsive-table-table tbody td {
    padding: var(--space-sm) var(--space-md);
    border-bottom: 1px solid var(--color-border-light);
    font-size: var(--text-sm);
    vertical-align: middle;
}

.responsive-table-table tbody tr:hover {
    background: var(--color-surface);
}

.responsive-table-cards {
    display: none;
    flex-direction: column;
    gap: var(--space-md);
}

.responsive-table-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    padding: var(--space-md);
    box-shadow: var(--elevation-1);
}

.responsive-table-empty {
    padding: var(--space-xl);
    text-align: center;
    color: var(--color-text-muted);
    background: var(--color-surface);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
}

/* Switch to card layout below ~600px container width. */
@container (max-width: 599px) {
    .responsive-table-table {
        display: none;
    }

    .responsive-table-cards {
        display: flex;
    }
}

/* Fallback for engines without container queries (Chrome <105, Safari <16, Firefox <110):
   approximate the container switch with a viewport query, so narrow screens still get the card
   layout instead of a wide table with nowhere to go. Inert wherever container queries work —
   CSS.supports('container-type: inline-size') is true in the capture engine, so `not (...)`
   never matches and all 12 consumer routes re-capture unchanged.

   647px is measured, and it is an APPROXIMATION BY NATURE — which is the whole reason the real
   rule is a container query. The container is not the viewport: it runs 50px narrower than the
   viewport on /Siba/StatusSiba and 48px narrower on /Admin/Roadmap, so the real switch
   (container 600) lands at viewport 650 on one page and 648 on the other. No single viewport
   number can serve both. 647 is the conservative end: it never shows cards where the container
   query would show a table, at the cost of switching up to 2px early on StatusSiba.

   One case no viewport query can reproduce: at 900px the sidebar appears and takes ~300px, so
   the container drops back under 600 and the cards legitimately return. Measured on the
   Invoicing twin; no baseline covers 900px, so the gate never saw it either. */
@supports not (container-type: inline-size) {
    @media (max-width: 647px) {
        .responsive-table-table {
            display: none;
        }

        .responsive-table-cards {
            display: flex;
        }
    }
}


/* ── inlined: primitives/auth-card.css ── */
/* ==========================================================================
   Auth surface shared styles
   Hoisted from per-page scoped CSS so the rules and @keyframes live in one
   place. Used by Login, Register, ChangePassword, AccessDenied, and any
   future page that uses the .auth-card layout inside AuthLayout.
   ========================================================================== */

.auth-container {
    width: 100%;
    max-width: 420px;
    margin: 0 auto;
}

.auth-card {
    background: var(--color-background);
    border-radius: var(--radius-lg);
    box-shadow: var(--elevation-4);
    padding: var(--spacing-xl);
    animation: auth-card-in var(--duration-base) var(--ease-out);
}

@keyframes auth-card-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}

.auth-header {
    text-align: center;
    margin-bottom: var(--spacing-lg);
}

.auth-header h1 {
    color: var(--color-primary);
    margin-bottom: var(--spacing-xs);
}

.auth-subtitle {
    color: var(--color-text-muted);
    margin-bottom: 0;
}

.auth-divider {
    display: flex;
    align-items: center;
    margin: var(--spacing-md) 0;
    color: var(--color-text-muted);
    font-size: 0.85rem;
}

.auth-divider::before,
.auth-divider::after {
    content: '';
    flex: 1;
    border-bottom: 1px solid var(--color-border);
}

.auth-divider span {
    padding: 0 var(--spacing-sm);
}

.auth-link {
    color: var(--color-secondary);
    text-decoration: none;
    font-weight: 500;
}

.auth-link:hover {
    color: var(--color-primary);
    text-decoration: underline;
}

@media (max-width: 575.98px) {
    .auth-card {
        padding: var(--spacing-lg);
    }
}


/* Bootstrap dark-mode chrome — global overrides for .alert / .badge /
   .form-control / .table / .pagination so every page that uses Bootstrap
   chrome gets the right dark colours without per-page duplication.
   See brief §6.3 convention: Bootstrap classes here; custom classes in
   each page's scoped .razor.css. */

/* ── inlined: bootstrap-dark.css ── */
/* ==========================================================================
   Bootstrap dark-mode chrome — global overrides
   Bootstrap 5's default colours (alert backgrounds, badge variants, form
   control bg/border, table chrome, pagination chrome, link colours inside
   alerts) are designed for light surfaces. Without overrides they sit as
   bright white blocks on the dark page background. This file consolidates
   the cross-cutting dark-mode rules so every page that uses these Bootstrap
   classes gets them for free — no per-page duplication.

   Convention (per brief §6.3):
     - Bootstrap class dark-mode overrides → THIS FILE
     - Page-specific custom class overrides → the page's scoped .razor.css

   Loaded via site.css's @import chain, AFTER Bootstrap (so its rules win)
   and BEFORE component-scoped CSS (so per-page rules can still override
   per-component if needed).

   No `b-XXX` scope attributes here — global CSS targets DOM elements
   directly, regardless of which component rendered them. That means
   InputText / InputDate / ValidationSummary / etc. all get the right
   chrome without any `::deep` gymnastics from consumers.
   ========================================================================== */

/* ── .card chrome ──────────────────────────────────────────────────────── */
[data-theme="dark"] .card {
    background-color: var(--color-surface);
    border-color: var(--color-border-light);
    color: var(--color-text);
}

[data-theme="dark"] .card-header {
    background-color: var(--color-background);
    border-bottom-color: var(--color-border-light);
}

/* ── .alert variants ────────────────────────────────────────────────────── */
[data-theme="dark"] .alert-warning {
    background-color: #3A2A0A;
    border-color: #6B4D14;
    color: #FCD34D;
}
[data-theme="dark"] .alert-danger {
    background-color: #3A1414;
    border-color: #7A2828;
    color: #FCA5A5;
}
[data-theme="dark"] .alert-success {
    background-color: #143820;
    border-color: #2A6038;
    color: #6FE291;
}
[data-theme="dark"] .alert-info {
    background-color: #1A2E3D;
    border-color: #2A5470;
    color: #93C5FD;
}

/* ── .alert-link inside each variant ──────────────────────────────────────
   Bootstrap's default .alert-link colour (a darker shade of the variant's
   hue) is designed for light alert surfaces. On our dark alert surfaces it
   reads near-invisible. Lift each link to a brighter tint of its variant. */
[data-theme="dark"] .alert-warning .alert-link { color: #FDE68A; }
[data-theme="dark"] .alert-danger  .alert-link { color: #FECACA; }
[data-theme="dark"] .alert-success .alert-link { color: #86EFAC; }
[data-theme="dark"] .alert-info    .alert-link { color: #BFDBFE; }

/* ── .badge variants ────────────────────────────────────────────────────── */
[data-theme="dark"] .badge.bg-secondary {
    background-color: #4A5568 !important;
    color: #E2E8F0 !important;
}
[data-theme="dark"] .badge.bg-info {
    background-color: #1E40AF !important;
    color: #BFDBFE !important;
}
[data-theme="dark"] .badge.bg-warning {
    background-color: #92400E !important;
    color: #FDE68A !important;
}
[data-theme="dark"] .badge.bg-success {
    background-color: var(--state-live-bg) !important;
    color: var(--state-live-fg) !important;
}
[data-theme="dark"] .badge.bg-danger {
    background-color: #3A1414 !important;
    color: #FCA5A5 !important;
}

/* ── .btn-outline-secondary (stock #6c757d text is 3.5:1 on --color-surface) ── */
/* Text and border move to the muted text token (~7:1). Set through Bootstrap's own variables so
   :hover / :active keep their stock fill and white text (4.7:1). */
[data-theme="dark"] .btn-outline-secondary {
    --bs-btn-color: var(--color-text-muted);
    --bs-btn-border-color: var(--color-text-muted);
}

/* ── .form-control / .form-select (Bootstrap defaults are white-on-white) ── */
[data-theme="dark"] .form-control,
[data-theme="dark"] .form-select {
    background-color: var(--color-surface);
    border-color: var(--color-border-light);
    color: var(--color-text);
    /* Native widget chrome (the time/date picker indicator and its popup) follows
       color-scheme, not `color`: without this Chromium paints the indicator black. */
    color-scheme: dark;
}

/* Disabled: the rule above has the same specificity as Bootstrap's :disabled fill and loads
   later, so without this a disabled control looks identical to an enabled one. */
[data-theme="dark"] .form-control:disabled,
[data-theme="dark"] .form-select:disabled {
    background-color: var(--color-surface-alt);
    color: var(--color-text-muted);
}

[data-theme="dark"] .form-control:focus,
[data-theme="dark"] .form-select:focus {
    background-color: var(--color-surface);
    border-color: var(--color-secondary);
    color: var(--color-text);
    box-shadow: 0 0 0 0.2rem rgba(91, 160, 232, 0.25);
}

[data-theme="dark"] .form-control::placeholder {
    color: var(--color-text-muted);
    opacity: 0.5;
}

/* ── .form-label (Bootstrap inherits; some pages set explicitly) ──────── */
[data-theme="dark"] .form-label {
    color: var(--color-text);
}

/* ── .validation-errors (rendered by Blazor's ValidationSummary) ──────── */
[data-theme="dark"] .validation-errors {
    background-color: #3A1414;
    border-color: #7A2828;
    color: #FCA5A5;
}

/* ── .table chrome ────────────────────────────────────────────────────── */
[data-theme="dark"] .table {
    color: var(--color-text);
}

[data-theme="dark"] .table > :not(caption) > * > * {
    background-color: var(--color-surface);
    color: var(--color-text);
    border-bottom-color: var(--color-border-light);
}

/* Some pages use a .table-header class on <thead>; cover both shapes. */
[data-theme="dark"] .table > thead > tr > th,
[data-theme="dark"] .table-header > tr > th {
    background-color: var(--color-background);
    color: var(--color-text);
    border-color: var(--color-border-light);
}

[data-theme="dark"] .table-hover > tbody > tr:hover > * {
    background-color: var(--color-background) !important;
    color: var(--color-text);
}

/* ── .pagination chrome ───────────────────────────────────────────────── */
[data-theme="dark"] .pagination .page-link {
    background-color: var(--color-surface);
    border-color: var(--color-border-light);
    color: var(--color-text);
}

[data-theme="dark"] .pagination .page-link:hover {
    background-color: var(--color-background);
    border-color: var(--color-secondary);
    color: var(--color-secondary);
}

[data-theme="dark"] .pagination .page-link:focus {
    background-color: var(--color-background);
    border-color: var(--color-secondary);
    color: var(--color-secondary);
    box-shadow: 0 0 0 0.2rem rgba(91, 160, 232, 0.25);
}

[data-theme="dark"] .pagination .page-item.active .page-link {
    background-color: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-text-on-primary);
}

[data-theme="dark"] .pagination .page-item.disabled .page-link {
    background-color: var(--color-surface);
    border-color: var(--color-border-light);
    color: var(--color-text-muted);
    opacity: 0.6;
}

/* ── .nav-tabs chrome ──────────────────────────────────────────────────
   Bootstrap default: active tab fills with white bg + dark text + a
   white bottom-border that masks the outer .nav-tabs hairline. On dark
   surfaces the white bg becomes a stark white block. Lift to surface +
   border tokens; the active tab gets --color-surface so it visually sits
   on top of the card body beneath it. */
[data-theme="dark"] .nav-tabs {
    border-bottom-color: var(--color-border-light);
}

[data-theme="dark"] .nav-tabs .nav-link {
    color: var(--color-text-muted);
    background-color: transparent;
    border-color: transparent;
}

[data-theme="dark"] .nav-tabs .nav-link:hover,
[data-theme="dark"] .nav-tabs .nav-link:focus {
    color: var(--color-text);
    border-color: var(--color-border-light) var(--color-border-light) transparent;
}

[data-theme="dark"] .nav-tabs .nav-link.active,
[data-theme="dark"] .nav-tabs .nav-item.show .nav-link {
    background-color: var(--color-surface);
    border-color: var(--color-border-light) var(--color-border-light) var(--color-surface);
    color: var(--color-text);
}

/* ── <pre> code blocks anchored to .bg-light ─────────────────────────────
   .bg-light flips to --color-surface in dark via tokens/_dark.css, but
   default <pre> text colour stays dark — illegible on the new surface.
   Lift the text + scrollbar tint so embedded code reads on dark. */
[data-theme="dark"] pre.bg-light {
    color: var(--color-text);
}

/* ── .list-group chrome ───────────────────────────────────────────────── */
[data-theme="dark"] .list-group {
    --bs-list-group-bg: var(--color-surface);
    --bs-list-group-color: var(--color-text);
    --bs-list-group-border-color: var(--color-border-light);
    --bs-list-group-action-color: var(--color-text);
    --bs-list-group-action-hover-color: var(--color-text);
    --bs-list-group-action-hover-bg: var(--color-surface-alt);
    --bs-list-group-action-active-bg: var(--color-surface-alt);
    --bs-list-group-action-active-color: var(--color-text);
}

[data-theme="dark"] .list-group-item {
    background-color: var(--color-surface);
    border-color: var(--color-border-light);
    color: var(--color-text);
}


/* Bootstrap light-mode contrast fixes (WCAG AA) — see the file header. */

/* ── inlined: bootstrap-contrast.css ── */
/* ==========================================================================
   Bootstrap light-mode contrast fixes — WCAG 2.1 AA (4.5:1) for normal text.

   Bootstrap 5.3's stock theme colours are used by .btn-outline-* as TEXT on a
   light surface, where several of them fail AA. Measured by the authenticated
   axe gate (tests/AL.Web.UI.E2E/Accessibility) across 46 states:

     .btn-outline-secondary  #6c757d on #eef2f7 = 4.17:1
     .btn-outline-primary    #0d6efd on #f8f9fa = 4.27:1
     .btn-outline-danger     #dc3545 on #f8f9fa = 4.30:1
     .btn-outline-success    #198754 on #fff3cd = 4.09:1
     code                    #d63384 on #fcfcfd = 4.39:1
     .badge.bg-info          #ffffff on #0dcaf0 = 1.96:1

   Only the TEXT colour is darkened (1–6%), never the border or background, so
   the buttons look the same — the shift is below perceptual threshold.

   The .btn-outline-* rules set Bootstrap's --bs-btn-color, not `color`: .btn paints
   `color: var(--bs-btn-color)` at rest and swaps to --bs-btn-hover-color / -active-color
   on :hover / :active. A plain `color` here outranks those state rules (0,2,1 vs 0,2,0),
   so hovered buttons kept this dark text on Bootstrap's dark hover fill and the label
   vanished (#666f76 on #6c757d). The
   badge flips to dark text, which is Bootstrap's own guidance for .bg-info and
   takes it to 7.9:1.

   LIGHT THEME ONLY. Dark mode uses different surfaces, so these exact pairings do
   not arise there. Dark contrast fixes (e.g. .btn-outline-secondary) live in
   bootstrap-dark.css.

   .btn-outline-warning (#ffc107, 1.63:1) and .btn-outline-info (#0dcaf0, 1.86:1)
   are ALSO fixed below, but they are a different kind of change: a 38–41% shift,
   yellow to olive and cyan to teal, which IS visible. Approved deliberately after
   review of the rendered comparison — not a silent tweak like the block above.
   ========================================================================== */

html:not([data-theme="dark"]) .btn-outline-secondary { --bs-btn-color: #666f76; }
html:not([data-theme="dark"]) .btn-outline-primary   { --bs-btn-color: #0c6af5; }
html:not([data-theme="dark"]) .btn-outline-danger    { --bs-btn-color: var(--color-danger-dark); }
html:not([data-theme="dark"]) .btn-outline-success   { --bs-btn-color: #177e4e; }
html:not([data-theme="dark"]) code                   { color: #d33282; }

/* White on #0dcaf0 is 1.96:1; Bootstrap pairs .bg-info with dark text for exactly
   this reason. Left unscoped rather than light-only: in dark mode bootstrap-dark.css
   overrides both the badge background AND its text with !important, so this rule is
   inert there. Scoping it would imply a dark pairing that never actually renders. */
.badge.bg-info { color: #212529; }

/* The two stock Bootstrap colours that need a VISIBLE shift, plus Bootstrap's link colour where
   the app points it at the azulejo blue. Unlike the 1–6% nudges above these are perceptible —
   #ffc107 sits at 1.63:1 on white and #0dcaf0 at 1.86:1, so yellow moves to olive and cyan to
   teal. Approved deliberately after reviewing the rendered before/after, not a silent tweak.
   .btn-link reuses --color-secondary-dark (ds-v1.1.6) rather than a literal. */
html:not([data-theme="dark"]) .btn-outline-warning { --bs-btn-color: #967104; }
html:not([data-theme="dark"]) .btn-outline-info    { --bs-btn-color: #087d94; }
html:not([data-theme="dark"]) .btn-link            { color: var(--color-secondary-dark); }


/* Icon-font subset + full-font fallback family — must come after the
   bootstrap-icons stylesheet in document order (it does: this file is
   linked after bootstrap-icons.min.css) so its font-family override wins.
   KEEP LAST: SmokeTests pins a marker from the final @import in the chain. */

/* ── inlined: icon-font-subset.css ── */
/* ==========================================================================
   Icon-font subset fallback (audit 2.3 / scripts/subset-icons.ps1)

   fonts/bootstrap-icons.woff2 is a SUBSET containing only the glyphs the
   source code uses (~10-20 kB instead of ~131 kB). The untouched official
   font ships alongside as bootstrap-icons.full.woff2 and is declared here as
   a per-glyph fallback family: when a rendered glyph is missing from the
   subset — e.g. an icon class an admin types into AdminRoadmap at runtime —
   the browser falls through to this family and lazy-downloads the full font
   ONLY then. Nothing is ever a blank box; everyone else pays only the subset.

   Loaded via site.css, which the document links AFTER bootstrap-icons.min.css,
   so the equal-specificity !important override below wins in the cascade.
   Selector list mirrors bootstrap-icons.min.css's own.
   ========================================================================== */

@font-face {
    font-family: "bootstrap-icons-full";
    font-display: block;
    src: url("../bootstrap-icons/fonts/bootstrap-icons.full.woff2") format("woff2"),
         url("../bootstrap-icons/fonts/bootstrap-icons.full.woff") format("woff");
}

.bi::before,
[class^="bi-"]::before,
[class*=" bi-"]::before {
    font-family: bootstrap-icons, "bootstrap-icons-full" !important;
}

