:root {
    /* ---------- Brand palette ----------
       Derived from the MudBlazor theme in Components/Hedging/CpdTheme.cs,
       which is the single source of truth for colour (both palettes).

       The literal fallbacks are load-bearing, not belt-and-braces.
       --mud-palette-* exists only where a <MudThemeProvider> renders, and for
       a long time that was MudHosts.razor alone, rendered only by MainLayout
       — AuthLayout (/Account/Login) and LandingLayout (/) didn't nest into
       it and left --mud-palette-* undefined. Both now render their own
       provider too (see ThemeProviderHost.razor and the comment in
       AuthLayout.razor for why they use two different strategies), so the
       gap these fallbacks cover has narrowed to two edges rather than the
       whole page: Blazor Server's static prerendering pass (no JS runtime
       yet, so the OS/localStorage resolution hasn't run) and AuthLayout's
       page specifically, which is static SSR with no SignalR circuit ever
       and so can never run that resolution at all. MudBlazor.min.css
       supplies no defaults of its own — it only ever consumes
       var(--mud-palette-*).

       Without the fallbacks the whole palette collapses in those gaps:
       --cpd-surface-*, --cpd-border*, --cpd-text and --cpd-focus are all
       composed from --cpd-contrast / --cpd-contrast-rgb, so an undefined channel
       triplet makes every rgba() built on it invalid. Both pages are
       signed-out, so this is the first thing a user sees.

       Keep each fallback identical to the corresponding value in
       MudHosts.razor's PaletteDark; they are two spellings of one colour.

       Deliberately NOT aliased (Mud's value is a different colour, not a
       different spelling of ours):
         --cpd-error   #e74c3c bright red  vs PaletteDark.Error   #b8324c crimson
         --cpd-success #27ae60 green       vs PaletteDark.Success #c8d96b olive-gold
       Border tokens below are likewise near-misses against Mud's divider vars
       (0.05/0.1/0.2 vs 0.06/0.08/0.12) and stay literal.

       --cpd-contrast is NOT "white" — it is "whichever colour contrasts with
       the current background" (PaletteDark.TextPrimary is white-on-black;
       PaletteLight.TextPrimary is near-black-on-ivory). Everything below
       that composes rgba(var(--cpd-contrast-rgb), alpha) reads as "dark
       overlay" in light mode and "light overlay" in dark mode, for free,
       because the channel triplet itself flips with the palette. This was
       --cpd-light / --cpd-light-rgb before light mode existed, when "light"
       and "white" were the same thing; renamed once they weren't, so the
       next reader isn't misled into thinking it's a literal colour. */
    --cpd-gold: var(--mud-palette-primary, #f6d46b);
    --cpd-gold-rgb: var(--mud-palette-primary-rgb, 246, 212, 107);
    /* PaletteDark.Background — NOT PaletteDark.Dark, which is a different colour. */
    --cpd-dark: var(--mud-palette-background, #061221);
    /* Background gets no -rgb export from Mud (confirmed against MudBlazor 9.5's
       generated :root style block — it emits -rgb triplets for Primary/Secondary/
       Tertiary/Text*/Action*/etc. but not for Background or Surface), so this
       cannot alias the same way --cpd-contrast-rgb does. It also can't be a plain
       literal across both themes: PaletteDark.Background (6,18,33) and
       PaletteLight.Background (247,243,234) are different colours, not a
       flip of the same one. Resolved via a `data-cpd-theme` attribute that
       ThemeProviderHost.razor keeps in sync with ThemeState — see the override
       a few lines down. Dark is the attribute-less default so pages that render
       no theme provider at all (a future regression of the MainLayout-only trap
       below) still get today's colour instead of an undefined one. */
    --cpd-dark-rgb: 6, 18, 33;
    --cpd-contrast: var(--mud-palette-text-primary, #ffffff);
    --cpd-contrast-rgb: var(--mud-palette-text-primary-rgb, 255, 255, 255);
    --cpd-accent: #d0d7e4;
    --cpd-error: #e74c3c;
    /* Component CSS composes this into rgba(). CSS cannot derive a channel
       triplet from a hex value, so it is spelled out here beside --cpd-error
       and must be kept in step with it. */
    --cpd-error-rgb: 231, 76, 60;
    --cpd-success: #27ae60;
    /* Unlike --cpd-error/--cpd-success above, Warning was never given a
       deliberately-different cpStudio literal — PaletteDark.Warning IS the
       brand's amber-orange (#f0a542) already, so this aliases straight
       through like --cpd-gold does. Added because mud-overrides.css's
       .text-warning read var(--mud-palette-warning) directly with no
       fallback, the one rule in that section not to use a --cpd-* token. */
    --cpd-warning: var(--mud-palette-warning, #f0a542);
    --cpd-focus: rgba(var(--cpd-gold-rgb), 0.30);

    /* ---------- Typography ---------- */
    --cpd-font-sans: 'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;
    --cpd-font-mono: 'SF Mono', 'Cascadia Code', 'Fira Code', 'Consolas', monospace;

    /* ---------- Surfaces (elevation on dark background) ---------- */
    --cpd-surface-0: var(--cpd-dark);
    --cpd-surface-1: rgba(var(--cpd-contrast-rgb), 0.02);
    --cpd-surface-2: rgba(var(--cpd-contrast-rgb), 0.05);
    --cpd-surface-3: rgba(var(--cpd-contrast-rgb), 0.08);
    --cpd-surface-hover: rgba(var(--cpd-contrast-rgb), 0.12);
    /* Curve Capture dialog surfaces. All three must be OPAQUE — they cannot be
       rgba(var(--cpd-contrast-rgb), …) overlays like --cpd-surface-1/2/3 above:
       --cpd-surface-dialog sits over live chart content and
       --cpd-surface-table-header is a `position: sticky` header scrolling over
       its own rows, so any alpha lets what is behind bleed through.

       They are also a genuine per-theme pair rather than a flip of one colour,
       so each gets an explicit light value below, like --cpd-dark-rgb and
       --cpd-surface-raised.

       What they actually are, against the page (#061221) — the previous comment
       described all three as progressively darker, which is not what the values
       do, and there is no "dialog shell" among them:
         -dialog       (10,21,38) LIGHTER — floating readout over the chart
                       (.curve-chart-readout; gold border + soft shadow). Despite
                       the name, no dialog shell uses this.
         -inset        ( 5,15,28) DARKER  — recessed chart well
                       (.capture-chart-box)
         -table-header (11,26,46) LIGHTER — sticky grid header band
                       (table.capture-grid th; carries --cpd-gold text) */
    --cpd-surface-dialog: #0a1526;
    --cpd-surface-inset: #050f1c;
    --cpd-surface-table-header: #0b1a2e;

    /* Opaque "floating above the page" surface, for the handful of places that
       cannot use the composed rgba() surfaces above because they need a real
       opaque colour: native <select> option popups (three files hardcoded
       #1b2631 / #0a1929 for exactly this) and .pre-trade-table.

       Needs both theme values spelled out for the same reason --cpd-dark-rgb
       does — it is not a flip of one colour. In dark mode it sits a step ABOVE
       --cpd-dark so a popup reads as raised off the page; in light mode the
       page is already ivory, so plain white is the raised analogue. */
    --cpd-surface-raised: #1b2631;

    /* Second stop of the shared "panel" gradient:
         linear-gradient(135deg, rgba(var(--cpd-dark-rgb), a), rgba(var(--cpd-panel-sheen-rgb), a))
       used by .history-table-container, .stoch-panel, .instrument-switch-card,
       .quote-chart, .recon-table-card and .recon-detail-card — 9 sites across
       the Market and Analytics pages.

       The first stop was tokenised when light mode went in; this one was left as
       a literal rgba(10, 25, 47), so every one of those panels rendered as a
       diagonal fade from the ivory page colour into navy in light mode. It reads
       as a thick dark frame around the content, and it is the first thing on the
       Market page.

       It is the page colour "lifted" — lighter than --cpd-dark in dark mode, so
       in light mode it lifts the other way, off ivory toward white.

       NOT applied inside CurveAccordionNode.razor.css. That file uses this same
       navy as one rung of a 7-value nested-elevation ladder (.curve-section
       .level-0..3 plus the accordion item/header), and converting a single rung
       would leave level-1 fading from white into navy. That ladder wants doing as
       one piece — see the follow-up. */
    --cpd-panel-sheen-rgb: 10, 25, 47;

    /* Nesting-depth ladder for the Market page's curve accordion
       (CurveAccordionNode.razor.css: .curve-section.level-0..3 and the
       ::deep .curve-accordion item/header). Seven ad-hoc navy literals, all of
       which stayed navy in light mode and put a dark slab on an otherwise ivory
       page whenever a curve was expanded.

       Each rung keeps its dark value EXACTLY as it was, so dark mode is
       untouched; the rungs are near-duplicates of each other because that is how
       they were written, not because seven steps are needed.

       The direction inverts between themes, which is why these cannot reuse
       --cpd-panel-sheen-rgb above. On the near-black page, "deeper" reads as
       progressively LIGHTER (further from #061221). On ivory there is almost no
       headroom upward — #f7f3ea to white is the whole range — so deeper reads as
       progressively DARKER instead, the usual way nested panels recess on a light
       background. --cpd-panel-sheen-rgb lifts toward white; this ladder sinks
       away from ivory. Same intent, opposite sign. */
    --cpd-nest-1-rgb: 10, 25, 47;
    --cpd-nest-2-rgb: 14, 32, 60;
    --cpd-nest-3-rgb: 16, 36, 66;
    --cpd-nest-4-rgb: 18, 40, 72;
    --cpd-nest-5-rgb: 20, 42, 70;
    --cpd-nest-6-rgb: 22, 46, 82;
    --cpd-nest-7-rgb: 30, 58, 98;
    --cpd-nest-8-rgb: 28, 55, 88;

    /* Keyword token for the `color-scheme` property — see the html,body rule. */
    --cpd-color-scheme: dark;

    /* Multiplier on the alpha of every muted TEXT colour built from
       --cpd-contrast-rgb. Applied to `color:` and `fill:` declarations only,
       never to background or border — those want to stay as faint as they are.

       An alpha overlay is not symmetric between the two themes. 0.4 white over
       #061221 measures 4.6:1; the same 0.4 of near-black over #f7f3ea measures
       only 2.5:1, because the light background starts much closer to the
       overlay's own luminance than the dark one does. So one alpha ladder tuned
       against dark mode silently under-delivers contrast at every rung in light
       mode — it left every 10px caption, slider tick and tile title on the
       trade-capture form washed out even after they started flipping colour
       correctly. 1.6 lifts the 0.4 rung to 0.64 (~4.6:1, matching what dark
       mode gets) and the 0.3 rung to 0.48. CSS clamps alpha at 1, so the top of
       the ladder (0.65 and up) is unaffected in both themes. */
    --cpd-text-alpha-scale: 1;

    /* ---------- Borders ---------- */
    --cpd-border-subtle: rgba(var(--cpd-contrast-rgb), 0.05);
    --cpd-border: rgba(var(--cpd-contrast-rgb), 0.1);
    --cpd-border-strong: rgba(var(--cpd-contrast-rgb), 0.2);

    /* ---------- Text levels ---------- */
    --cpd-text: var(--cpd-contrast);
    --cpd-text-muted: var(--cpd-accent);
    /* Scaled like the inline `color:` sites — this tier is only ever used as a
       text colour, so it belongs on the same ladder. */
    --cpd-text-subtle: rgba(var(--cpd-contrast-rgb), calc(0.4 * var(--cpd-text-alpha-scale)));

    /* ---------- Gold tints (consistent across components) ---------- */
    --cpd-gold-faint:  rgba(var(--cpd-gold-rgb), 0.04);
    --cpd-gold-soft:   rgba(var(--cpd-gold-rgb), 0.08);
    --cpd-gold-tint:   rgba(var(--cpd-gold-rgb), 0.15);
    --cpd-gold-strong: rgba(var(--cpd-gold-rgb), 0.25);
    --cpd-gold-border: rgba(var(--cpd-gold-rgb), 0.3);
    --cpd-gold-ring:   rgba(var(--cpd-gold-rgb), 0.1);

    /* ---------- Spacing scale ---------- */
    --cpd-space-xs:  0.25rem;
    --cpd-space-sm:  0.5rem;
    --cpd-space-md:  0.75rem;
    --cpd-space-lg:  1rem;
    --cpd-space-xl:  1.5rem;
    --cpd-space-2xl: 2rem;
    --cpd-space-3xl: 3rem;

    /* ---------- Radii ---------- */
    --cpd-radius-sm: 4px;
    --cpd-radius-md: 6px;
    --cpd-radius-lg: 8px;
    --cpd-radius-xl: 12px;
    --cpd-radius-pill: 999px;

    /* ---------- Transitions ---------- */
    --cpd-transition-fast:  0.15s ease;
    --cpd-transition:       0.25s ease;
    --cpd-transition-slow:  0.3s ease;

    /* ---------- Shadows ---------- */
    --cpd-shadow-card: 0 8px 32px rgba(0, 0, 0, 0.3);
    --cpd-shadow-soft: 0 2px 8px rgba(0, 0, 0, 0.2);
}

/* Light-mode values for the two tokens that cannot express both themes in a
   single declaration — see the comments on their dark defaults above.
   `data-cpd-theme` is set on <html> by ThemeProviderHost.razor, kept in sync
   with ThemeState (both at first paint and on every toggle). An attribute
   selector beats a bare :root selector on specificity, so these win
   regardless of source order. */
:root[data-cpd-theme="light"] {
    /* PaletteLight.Background is #f7f3ea. */
    --cpd-dark-rgb: 247, 243, 234;

    /* See the dark default for why this needs both values written out. */
    --cpd-surface-raised: #ffffff;
    --cpd-color-scheme: light;

    /* Ivory lifted toward white, mirroring how the dark value lifts #061221.
       Deliberately subtle: the dark gradient is a barely-there sheen, not a
       visible two-tone, and it should stay that way here. */
    --cpd-panel-sheen-rgb: 255, 253, 247;

    /* Curve-accordion nesting ladder — sinking away from ivory rather than
       lifting toward white; see the dark defaults for why the sign flips. */
    --cpd-nest-1-rgb: 242, 237, 226;
    --cpd-nest-2-rgb: 238, 232, 220;
    --cpd-nest-3-rgb: 234, 227, 213;
    --cpd-nest-4-rgb: 231, 224, 208;
    --cpd-nest-5-rgb: 236, 229, 215;
    --cpd-nest-6-rgb: 228, 220, 203;
    --cpd-nest-7-rgb: 223, 214, 195;
    --cpd-nest-8-rgb: 219, 209, 188;

    /* Curve Capture surfaces. The dark set steps AWAY from the page in both
       directions (raised things lighter, the chart well darker); mirrored here,
       "raised" becomes lighter than ivory and "recessed" becomes darker. Note
       the dialog's own paper is PaletteLight.Surface (#ffffff), not the ivory
       page, so these are judged against white where they sit inside it.

         -dialog       white, over the #eee8dc chart well — reads as raised, and
                       it already carries a gold border and --cpd-shadow-soft.
         -inset        one warm step below the white dialog paper: a recessed
                       well. The chart's own marks stay legible on it (axis
                       labels 4.0:1, the darkest series 4.5:1).
         -table-header the ivory page colour, which is the one value that works
                       here. It has to differ from the white rows AND carry
                       --cpd-gold text, and in light mode that gold is
                       PaletteLight.Primary (#8a6a1f) — only 5.05:1 on white to
                       begin with, so every step of tint eats the margin: at
                       #ece4d4 the gold is down to 4.0:1. Ivory keeps it at
                       4.56:1 and still tints away from the rows; the band is
                       drawn by the 2px gold bottom border the rule already has,
                       which is what separates it in dark mode too. */
    --cpd-surface-dialog: #ffffff;
    --cpd-surface-inset: #eee8dc;
    --cpd-surface-table-header: #f7f3ea;
    --cpd-text-alpha-scale: 1.6;

    /* --cpd-accent feeds --cpd-text-muted, used on ~68 sites (landing copy,
       placeholders, wizard labels, chart and table annotations). Its dark
       default #d0d7e4 is a pale blue-grey that sits at roughly 1.3:1 against
       the ivory light background — effectively invisible. This is
       PaletteLight.TextSecondary.

       Overridden here rather than aliased to var(--mud-palette-text-secondary)
       at the definition, because that variable is rgba(255,255,255,0.65) in
       dark mode and would silently restyle all 68 sites in the theme that
       ships today. Keeping the dark default literal confines this fix to
       light mode. */
    --cpd-accent: rgba(13, 21, 34, 0.65);
}

/* ---------- Global reset ----------------------------------- */
*{box-sizing:border-box;margin:0;padding:0}

/* Remove focus outline on headings set by Blazor's FocusOnNavigate */
h1:focus{outline:none}

html,
body{
    font-family: var(--cpd-font-sans);
    background: var(--cpd-surface-0);
    color: var(--cpd-text);
    /* Tells the UA which way to render the parts of native widgets that CSS
       cannot reach — <select>'s dropdown arrow and popup, date/number input
       spinners, scrollbars, autofill. Capture.razor.css pinned this to `dark`
       on two rules, which left those widget internals dark-on-ivory in light
       mode; both now read this token instead. It has to be a keyword in a
       variable because color-scheme takes no colour value to derive it from. */
    color-scheme: var(--cpd-color-scheme);
}

html, body { height: 100%; }
body { overflow-x: hidden; }


/* remove default link colour / underlines everywhere */
a,a:hover,a:visited,a:focus,a:active{
    text-decoration:none;
    color:inherit;
}

/* ---------- Header / branding ------------------------------ */
.landing-header{
    position:fixed;top:0;left:0;width:100%;
    background:var(--cpd-surface-0);
    padding:1rem 0;
    z-index:100;
    border-bottom:1px solid var(--cpd-border-subtle);
}
.container{
    width:min(90%,1200px);
    margin-inline:auto;
    display:flex;
    align-items:center;
    justify-content:space-between;
}

/* brand mark */
.brand{
    font-size:1.6rem;font-weight:600;
    color:var(--cpd-contrast);
    transition:color .25s;
}
.brand:hover{color:#b6bdc9}
.brand .logo-accent{color:var(--cpd-gold)}
.brand:hover .logo-accent{color:var(--cpd-gold)}

/* primary nav */
.nav-links{display:flex;gap:3rem;list-style:none}
.nav-links a{font-weight:500;color:var(--cpd-contrast)}
.nav-links a:hover{color:var(--cpd-gold)}
@media(max-width:768px){.nav-links{gap:1.5rem}}

/* ---------- Buttons ---------------------------------------- */
.btn-link{color:var(--cpd-gold);transition:color .25s}
.btn-link:hover{color:var(--cpd-contrast)}

.btn-outline-gold,.btn-gold{
    padding:.55rem 1.35rem;
    border-radius: var(--cpd-radius-md);
    transition: background var(--cpd-transition), color var(--cpd-transition);
}

/* outline */
.btn-outline-gold{
    border:1px solid var(--cpd-gold);
    background:transparent;
    color:var(--cpd-gold);
}
.btn-outline-gold:hover{
    background:var(--cpd-gold);
    color:var(--cpd-dark);
}

a.btn-gold, .btn-gold {
    background: var(--cpd-gold) !important;
    color: var(--cpd-dark) !important;
    border: 1px solid var(--cpd-gold) !important;
    padding: .55rem 1.35rem;
    border-radius: var(--cpd-radius-md);
    transition: background var(--cpd-transition), color var(--cpd-transition);
}
a.btn-gold:hover, .btn-gold:hover {
    background: var(--cpd-dark) !important;
    color: var(--cpd-gold) !important;
}

/* focus ring */
.btn:focus,
.btn:active:focus,
.btn-link.nav-link:focus,
.form-control:focus,
.form-check-input:focus{
    box-shadow:0 0 0 .1rem var(--cpd-dark),
               0 0 0 .25rem var(--cpd-focus);
}

/* ---------- Forms ------------------------------------------ */
.form-control{
    background: var(--cpd-surface-2);
    border: 1px solid var(--cpd-border);
    color: var(--cpd-text);
}
    .form-control:focus {
        background: var(--cpd-surface-3);
        border-color: var(--cpd-gold);
        color: var(--cpd-text);
    }
.form-control::placeholder{color: var(--cpd-text-muted)}
.darker-border-checkbox.form-check-input{border-color: var(--cpd-text-muted)}

/* ---------- Validation colours ----------------------------- */
.valid.modified:not([type=checkbox]){outline:1px solid var(--cpd-success)}
.invalid{outline:1px solid var(--cpd-error)}
.validation-message{color:var(--cpd-error)}

/* ---------- Blazor error banner ---------------------------- */
.blazor-error-boundary{
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding:1rem 1rem 1rem 3.7rem;
    color: var(--cpd-text);
    border-radius: var(--cpd-radius-md);
}
.blazor-error-boundary::after{content:"An error has occurred."}

.hero{min-height:calc(100vh - 4.75rem);display:flex;align-items:center;position:relative;overflow:hidden}
.hero-inner{
    display:grid;grid-template-columns:1fr 1fr;
    align-items:center;gap:4rem;
}
@media(max-width:992px){
    .hero-inner{grid-template-columns:1fr;gap:3rem}
    .visual{justify-self:center}
}
@media(max-width:768px){
    .copy h1{font-size:2.8rem}
    .copy p {font-size:1.1rem}
}

.logo-accent { color: var(--cpd-gold); }


/* Menu Tree */
.bb-sidebar2-top-row.navbar {
    display: none !important;
}

.cp-nav-item {
     background-color: var(--cpd-surface-0) !important;
}
.nav-container {
    background: var(--cpd-surface-1);
}

.modal-content {
    background-color: var(--cpd-surface-0) !important;
    color: var(--cpd-text) !important;
    border: 1px solid var(--cpd-gold-border) !important;
    border-radius: var(--cpd-radius-lg) !important;
}

.modal-header {
    background: rgba(var(--cpd-contrast-rgb), 0.03) !important;
    border-bottom: 1px solid rgba(var(--cpd-gold-rgb), 0.2) !important;
    color: var(--cpd-text) !important;
}

.modal-header .modal-title {
    font-weight: 600;
    font-size: 1rem;
}

.modal-header .btn-close {
    filter: invert(1) !important;
}

.modal-body {
    background-color: transparent !important;
    color: var(--cpd-text) !important;
    font-size: 0.95rem;
}

.modal-footer {
    background: rgba(var(--cpd-contrast-rgb), 0.03) !important;
    border-top: 1px solid rgba(var(--cpd-gold-rgb), 0.2) !important;
}

.modal-footer .btn-secondary {
    background-color: var(--cpd-surface-3) !important;
    border: 1px solid var(--cpd-border-strong) !important;
    color: var(--cpd-text) !important;
}

.modal-footer .btn-secondary:hover {
    background-color: var(--cpd-surface-hover) !important;
}

.form-text {
    color: var(--cpd-text-muted) !important;
}

.alert-danger {
    background-color: #5a1d1d !important;
    border-color: #842029 !important;
    color: #ea868f !important;
}

.alert-info {
    background-color: var(--cpd-gold-soft) !important;
    border-color: var(--cpd-gold-border) !important;
    color: var(--cpd-gold) !important;
}

.alert-success {
    background-color: rgba(39, 174, 96, 0.1) !important;
    border-color: rgba(39, 174, 96, 0.3) !important;
    color: var(--cpd-success) !important;
}

.bb-sidebar2 .nav-link {
    display: flex !important;
    align-items: flex-start !important;
    gap: 0.4rem !important;
    padding: 0.55rem 0.5rem !important;
    border-radius: var(--cpd-radius-sm);
    transition: background var(--cpd-transition-fast), color var(--cpd-transition-fast);
}

.bb-sidebar2 .nav-link:hover {
    background: rgba(var(--cpd-gold-rgb), 0.12);
    color: var(--cpd-gold) !important;
}

.bb-sidebar2 .nav-link.active {
    background: rgba(var(--cpd-gold-rgb), 0.18) !important;
    color: var(--cpd-gold) !important;
}

.bb-sidebar2 .nav-link-icon,
.bb-sidebar2 .nav-link-arrow {
    flex: 0 0 auto !important;
    margin: 0 !important;
    padding: 0 !important;
    display: inline-flex !important;
    align-items: center !important;
    opacity: 0.85;
}

.bb-sidebar2 .nav-link-text,
.bb-sidebar2 .nav-link-text.ms-2 {
    flex: 1 1 0% !important;
    min-width: 0 !important;
    margin: 0 !important;
    padding: 0 !important;
    display: block !important;
    word-wrap: break-word !important;
    overflow-wrap: break-word !important;
    line-height: 1.4;
}

.bb-sidebar2 .nav-link-icon i,
.bb-sidebar2 .nav-link-arrow i {
    margin: 0 !important;
    padding: 0 !important;
}

.bb-sidebar2-content {
    padding: 0.35rem !important;
}

.bb-sidebar2 .nav-item {
    padding: 0.1rem 0.2rem !important;
    margin: 0 !important;
}

.bb-sidebar2 .nav-item .nav-item {
    margin-left: 1rem !important;
}

/* Shared block styling (Trade-section style cards).
   Authoritative copy lives in sandbox-page-base.css; keep this file free of
   duplicate rules. */

/* Ensure collapse animation works for ConventionDetails */
.object-child-area {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--cpd-transition-slow);
}

.object-child-area.show {
    grid-template-rows: 1fr;
}

.object-child-area-inner {
    overflow: hidden;
}

/* Convention custom schedule */
.convention-details-container {
    padding-top: 0.35rem;
}

.convention-display-grid {
    display: grid;
    gap: 0.85rem 1rem;
}

.convention-field {
    padding-bottom: 0.15rem;
}

.convention-schedule {
    grid-column: 1 / -1;
    padding-top: 0.25rem;
}

.convention-schedule-grid {
    display: grid;
    grid-template-columns: minmax(140px, 1fr) minmax(140px, 1fr) auto;
    gap: var(--cpd-space-sm);
    align-items: center;
}

.custom-periods {
    --schedule-col-start:    rgba(90, 156, 140, 0.95);
    --schedule-col-end:      rgba(90, 156, 140, 0.70);
    --schedule-col-notional: rgba(90, 156, 140, 0.50);
    --schedule-col-rate:     rgba(90, 156, 140, 0.85);
    --schedule-col-spread:   rgba(90, 156, 140, 0.40);
}

.custom-periods-grid,
.custom-periods-detailed .custom-periods-row {
    display: grid;
    grid-template-columns: minmax(130px, 1fr) minmax(130px, 1fr) minmax(110px, 0.9fr) minmax(95px, 0.75fr) minmax(95px, 0.75fr) auto;
    gap: 0.5rem;
    align-items: center;
}

.custom-periods-detailed .custom-periods-row {
    margin-bottom: 0.25rem;
}

.custom-periods-header-row {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.custom-periods .form-input[data-col]                            { border-bottom-width: 2px; border-bottom-style: solid; }
.custom-periods .form-input[data-col="start"]                    { border-bottom-color: var(--schedule-col-start); }
.custom-periods .form-input[data-col="end"]                      { border-bottom-color: var(--schedule-col-end); }
.custom-periods .form-input[data-col="notional"]                 { border-bottom-color: var(--schedule-col-notional); }
.custom-periods .form-input[data-col="rate"]                     { border-bottom-color: var(--schedule-col-rate); }
.custom-periods .form-input[data-col="spread"]                   { border-bottom-color: var(--schedule-col-spread); }
.custom-periods .convention-schedule-header[data-col="start"]    { color: var(--schedule-col-start); }
.custom-periods .convention-schedule-header[data-col="end"]      { color: var(--schedule-col-end); }
.custom-periods .convention-schedule-header[data-col="notional"] { color: var(--schedule-col-notional); }
.custom-periods .convention-schedule-header[data-col="rate"]     { color: var(--schedule-col-rate); }
.custom-periods .convention-schedule-header[data-col="spread"]   { color: var(--schedule-col-spread); }

.custom-period-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.convention-schedule-header {
    color: var(--cpd-text);
    font-weight: 600;
    font-size: 0.85rem;
}

.convention-schedule-actions {
    margin-top: var(--cpd-space-sm);
    display: flex;
    flex-wrap: wrap;
    gap: var(--cpd-space-sm);
}

.convention-schedule-import {
    margin-top: var(--cpd-space-md);
}

.convention-schedule-paste {
    width: 100%;
    min-height: 8rem;
    margin-top: 0.35rem;
    font-family: var(--cpd-font-mono);
}

.convention-schedule-help {
    margin-top: 0.4rem;
    color: var(--cpd-text);
    font-size: 0.8rem;
    opacity: 0.85;
}

.convention-schedule-error {
    margin-top: var(--cpd-space-sm);
    color: #f28b82;
    font-size: 0.85rem;
}

#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: 0; left: 0; width: 100%; z-index: 1000;
    background: #b32121;
    color: var(--cpd-text);
    padding: .6rem 1.25rem .7rem 3.7rem;
}
#blazor-error-ui .dismiss {
    position: absolute; right: .75rem; top: .5rem; cursor: pointer;
}
#blazor-error-ui .blazor-error-details {
    margin-top: .35rem;
}
#blazor-error-ui .blazor-error-details summary {
    cursor: pointer;
    text-decoration: underline;
}
#blazor-error-ui .blazor-error-details .token-banner-row {
    margin: .35rem 0;
}
#blazor-error-ui #blazor-error-detail {
    display: block;
    width: 100%;
    height: 14rem;
    resize: vertical;
    background: rgba(0, 0, 0, 0.35);
    color: var(--cpd-text);
    border: 1px solid rgba(var(--cpd-contrast-rgb), 0.35);
    border-radius: 4px;
    padding: .5rem;
    font-family: var(--cpd-font-mono);
    font-size: .78rem;
    white-space: pre;
}

/* Shared "requirement row" grammar for the Market/Editors' `Inline` markup (StochasticEditor,
   CreditEditor, ...) — used from both MarketDataRequirements (trade capture's Market Data pane)
   and MarketView, so it lives in the global stylesheet rather than a razor.css scoped to either
   host. `market-row-content` grows/shrinks with whatever each editor's own link/label/input looks
   like; `market-row-actions` clusters the row's model-options toggle and Set/Save button flush
   right. Because every row's actions cluster is pinned to the same right edge regardless of how
   wide its content is, each row's Set button lands in the same visual column as every other row's —
   this is what "Set" not lining up across rows (the Stochastic row in particular, which used to be
   a bare left-hugging flex row in a different control order) was missing. */
.market-row-inline {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    width: 100%;
}

.market-row-content {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
}

.market-row-actions {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

/* StochasticEditor's Inline compact field (json-component.css's `.json-token.mode-compact`, wrapping
   a plain <input>) sits at the bottom of a flex-shrink chain — market-row-content (flex:1 1 auto,
   min-width:0) > .json-token.mode-compact (flex:0 1 auto, min-width:3rem) > .repr-overlay-wrapper
   (flex:1 1 auto, min-width:0) — with no floor above 3rem/48px, so it shrinks to whatever the grid's
   Value column happens to offer rather than to its own content's size. Measured live against the
   HW1F default (`hw1f 0.05 0.01 act/365`, the exact string the xVA demo README has the presenter
   read out loud): clientWidth 150px vs a needed scrollWidth of 185px — 35px of clipped text. Floor
   it at 185px + ~10px of cross-browser/rounding slack so that default never clips; this also widens
   the shared Value column enough for every other row in the grid (same trade-off CreditEditor made
   for its numeric fields below). HW2F's compact grammar (`hw2f <a1> <a2> <sigma1> <sigma2> <rho>
   <daycount>`) is meaningfully longer than HW1F's and will still clip here — that's out of scope for
   this fix (HW2F has no seeded compact default to demo), but revisit this floor if that changes. */
.stochastic-compact-field .json-token.mode-compact {
    min-width: 195px;
}
