/*
   YieldSim site CSS.

   Strategy:
   - Lean on Bootstrap 5's built-in dark theme tokens (data-bs-theme="dark"
     is set on <html> in _Layout.cshtml). Most of the visual identity comes
     from those tokens; this file only adds the bits Bootstrap doesn't
     handle (subtle accent colors, modal padding, custom badges).
   - No alert()/confirm() helpers — all modal styling targets Bootstrap's
     .modal so the standard markup just works.
*/

:root {
    /* ── Chart color-coding palette ───────────────────────────────────────
       Used to differentiate XRP-denominated vs USD-denominated vs hybrid
       strategies wherever the user is reading the chart legend, the
       per-strategy accent stripe on assumption cards, or the page-accent
       ribbon. Picked once here so every chart and badge uses the same hue.
       Chart-coding palette is DELIBERATELY separate from the chrome accent
       below: color-coding wants diversity, chrome wants a single brand
       identity. Mixing them was the root of the previous "everything is
       blue" problem. */
    --yieldsim-accent-xrp: #4dabf7;        /* lighter blue, XRP-denominated */
    --yieldsim-accent-usd: #51cf66;        /* lighter green, USD-denominated */
    --yieldsim-accent-hybrid: #ffd43b;     /* yellow, hybrid portfolios */

    /* ── Two-axis scenario classification palette ─────────────────────────
       Replaces the old single-axis "ProbabilityTier" (Probable / Plausible
       / Extreme) which conflated "how often does this happen" with "how
       bad is it." The new pair lets each axis carry its own three-level
       palette, distinguishable side-by-side so a user reading two badges
       next to a scenario name immediately sees which dimension is which.

       Frequency ramp — green→yellow→red, the familiar "traffic light"
       reading that lines up with the user's prior expectation about
       likelihood. Hue family: pure greens / yellows / reds.

       Severity ramp — deliberately rotated to cool→warm so a green
       frequency badge sitting next to a green severity badge doesn't
       look like one big duplicate. Hue family: teal (mild damage) →
       amber (significant) → magenta-red (catastrophic). The contrast
       lets the eye scan "two greens = nothing-burger" vs "green + red =
       routine event but catastrophic damage when it lands" at a glance.

       Backward-compat shims for the old --yieldsim-tier-* names are kept
       BELOW so existing places that paint accent stripes (e.g. the
       Classroom Risk-and-recovery section card border) don't visually
       flip — those names now alias the closest equivalent in the new
       palette and can be removed in a follow-up cleanup once every call
       site has migrated. */
    --yieldsim-freq-routine:  #51cf66;     /* green, base-case shape */
    --yieldsim-freq-episodic: #ffd43b;     /* yellow, multiple-times-per-decade */
    --yieldsim-freq-rare:     #ff6b6b;     /* coral-red, handful per crypto era */

    --yieldsim-sev-mild:         #38d9a9;  /* teal — recovers within horizon */
    --yieldsim-sev-significant:  #ff922b;  /* amber — substantial drawdown */
    --yieldsim-sev-catastrophic: #e64980;  /* magenta-red — wipeout */

    /* ── Strategy-level risk-profile palette ──────────────────────────────
       Each strategy carries a 4-axis risk profile (Price / Counterparty /
       Smart-contract / Liquidity), and each axis is rated None/Low/Medium/
       High. The four levels share a single ramp so a user scanning a
       strategy's four-badge cluster immediately reads "two None + one Low
       + one High = mostly safe but watch the High dimension." Hue family
       chosen to NOT collide with frequency or severity above — neutral
       grey for None, blue-leaning for Low/Medium/High so the strategy-
       risk badges are visually distinct from scenario badges sitting on
       the same page. */
    --yieldsim-risk-none:   #495057;  /* neutral grey — "this risk doesn't apply" */
    --yieldsim-risk-low:    #4dabf7;  /* light blue */
    --yieldsim-risk-medium: #be4bdb;  /* purple */
    --yieldsim-risk-high:   #f783ac;  /* pink-red (less harsh than full red) */

    /* Backward-compat shims for the old tier vocabulary. Anywhere the
       Classroom or assumption pages painted an accent stripe via
       --yieldsim-tier-{probable,plausible,extreme} now resolves to the
       closest new palette equivalent. Marked deprecated; remove once
       every call site references the new variable names directly. */
    --yieldsim-tier-probable:  var(--yieldsim-freq-routine);
    --yieldsim-tier-plausible: var(--yieldsim-freq-episodic);
    --yieldsim-tier-extreme:   var(--yieldsim-freq-rare);

    /* ── App chrome accent (2026-05-27 palette pivot — REVISION 2) ──────────
       Operator directive: replace the wall-of-blue chrome (brand wordmark
       "Yield", slogan P-words, Run-simulation button, primary CTAs, link
       color, focus rings) with a deep blood red so the app reads as serious
       finance UI rather than "tech-startup azure." Chrome stays a SINGLE
       brand hue; chart color-coding above is the only place that
       legitimately wants diversity.

       Revision 1 used Tailwind rose-700/800/900 (#be123c / #9f1239 /
       #881337) — operator feedback: "pinkish hue ... I was expecting a
       deeper blood red." Rose family sits at hue ~343° (magenta lean);
       rotated to pure-red-hue family (0°) at deeper luminance.

       Revision 2 ramp — pure red, no pink:
         chrome        — #8b0000  (CSS "darkred"; deep pure blood)
         chrome-bright — #b30000  (one step brighter; for thin text + hover)
         chrome-deep   — #5c0000  (one step deeper; for press/border accents)

       Usage rule (load-bearing):
         - Filled surfaces (.btn-primary, .btn-info bg, run-sim base)
           → use BASE chrome (#8b0000). Surface area carries the deep feel.
         - Thin text / borders / icon hovers / link colors / nav-active /
           focus rings / slogan accents → use BRIGHT (#b30000). Thin marks
           on near-black need the extra luminance or they vanish.
         - Pressed states / deepest borders / halo edges → use DEEP (#5c0000).

       White text contrast on BASE chrome = ~9.0:1 (well above AA-AAA).
       Base on bg-page (#0a0a0a) = ~2.3:1 — sub-3:1 on its own, but the
       white text inside the button is what the user identifies, not the
       button vs page contrast. */
    --yieldsim-chrome:        #8b0000;
    --yieldsim-chrome-bright: #b30000;
    --yieldsim-chrome-deep:   #5c0000;

    /* Surface tones. Operator directive (Session of 2026-05-25): the navbar
       and the body must share the SAME near-black, no visible step between
       chrome and content — the previous deep/page split read as
       "dark navbar on top of a gray page," which broke the "black dark
       everywhere" intent. So bg-deep === bg-page.
       Pivot history:
         #0b0e12 (original)  — faint cool-blue tint (rgb 11/14/18, more
                               blue than red/green), read off-balance next
                               to warm red chrome.
         #0a0a0a (rev 1)     — fully neutral very-dark.
         #000000 (rev 2)     — operator: "as black as black can get."
                               Pure absolute black. Increases the card-to-
                               page luminance step, so .card.bg-body-tertiary
                               (which still sits at #161616) reads as
                               MORE elevated than it did against #0a0a0a.
                               Box-shadow on cards uses rgba(0,0,0,0.4) —
                               invisible on pure-black bg, but the blur
                               still feathers the card edge so the tile
                               retains a lifted appearance.
       Card + input surfaces stay where they were so elevated tiles
       (chart card, summary table) remain visibly distinct from the page. */
    --yieldsim-bg-deep:  #000000;
    --yieldsim-bg-page:  #000000;
    --yieldsim-bg-card:  #161616;
    --yieldsim-bg-input: #1e1e1e;

    /* Override Bootstrap 5 dark theme's default <code> colour (--bs-code-color
       defaults to #d63384, a magenta/pink) with a neutral light grey. The
       pink read as out-of-palette against the dark blue/green/yellow accents
       used everywhere else in the app and clashed with the educational tone. */
    --bs-code-color: #adb5bd;
}

/* === Session 10 contrast pass ===================================
   The previous palette was uniformly dim — cards blended into the
   body background, headings were off-white instead of pure white,
   nav links were near-muted gray, and the only saturated colours
   were on the chart itself. Overhaul:

   - Deeper page background so cards (which stay at body-tertiary)
     pop more.
   - Pure-white headings, with slightly tightened letter-spacing for
     a more confident editorial feel.
   - Accent-coloured primary buttons + form-focus rings using the
     existing XRP-blue palette token.
   - Brighter nav links with a clear hover state.
   - Stronger card shadows so the chart and reference-page cards
     read as elevated tiles, not flat sheets.
   - A 3-colour accent ribbon under the navbar so every page carries
     a thin visual signal of the brand palette.
   ================================================================= */

/* Re-bind Bootstrap dark theme tokens to our true-black + oxblood values. */
[data-bs-theme="dark"] {
    --bs-body-bg: var(--yieldsim-bg-page);
    /* Bootstrap's `.bg-body` UTILITY class — applied to `<body>` in
       _Layout.cshtml — uses --bs-body-bg-rgb (the comma-separated decimal
       triplet), NOT --bs-body-bg. If we only override the hex variant, the
       utility class falls back to Bootstrap's dark-theme default
       (33, 37, 41 == #212529 gray), which paints the body that visible
       gray regardless of how dark we make --bs-body-bg. So we MUST keep
       the two in lockstep: hex AND rgb. #000000 decomposes to 0, 0, 0.
       Same rule applies to --bs-tertiary-bg-rgb (powers `.bg-body-tertiary`
       which is on every .card in the app). Surface RGBs match the surface
       hexes in :root above; keep them in lockstep. */
    --bs-body-bg-rgb: 0, 0, 0;
    --bs-emphasis-color: #ffffff;
    --bs-emphasis-color-rgb: 255, 255, 255;
    --bs-tertiary-bg: var(--yieldsim-bg-card);
    --bs-tertiary-bg-rgb: 22, 22, 22;

    /* Link / focus chrome → blood red. Bootstrap reads --bs-link-color-rgb
       for utilities that build rgba() ramps (focus halos, faded states), so
       hex AND rgb both have to flip in lockstep — same gotcha as the bg
       tokens above. Link color leans on the BRIGHT chrome step because
       links are thin text — base #8b0000 is too low-luminance to read as
       an "active" affordance against near-black; bright #b30000 = 179,0,0
       gives enough lift. */
    --bs-link-color: var(--yieldsim-chrome-bright);
    --bs-link-color-rgb: 179, 0, 0;
    --bs-link-hover-color: #d40000; /* one step brighter than chrome-bright for the hover lift */

    /* Bootstrap's --bs-info family powered the "secondary chrome accent"
       in this app from day one — every .btn-info, .btn-outline-info, and
       .text-info usage (the brand wordmark "Yield", view-mode toggle on
       /assumptions, "Save override" CTA, info-modal Close button, "How is
       this used?" inline link) inherits from these tokens. Repointing the
       whole info family at chrome blood-red means every chrome surface
       follows in one swap, without churning markup. The XRP-blue
       chart-coding token above stays untouched — it powers the legend /
       assumption-card accent stripe / chart lines, which intentionally
       keep their own palette diversity.
       Like the link color above, --bs-info points at the BRIGHT step so
       .text-info (the wordmark "Yield" letters, inline info-color text)
       has enough luminance to read. Filled .btn-info surfaces re-pick the
       BASE in the .btn-info{} rule below; the token default leans bright
       because text-info usage is more common. */
    --bs-info: var(--yieldsim-chrome-bright);
    --bs-info-rgb: 179, 0, 0;
    --bs-info-text-emphasis: var(--yieldsim-chrome-bright);
    --bs-info-bg-subtle: rgba(179, 0, 0, 0.12);
    --bs-info-border-subtle: var(--yieldsim-chrome-deep);

    --bs-border-color-translucent: rgba(255, 255, 255, 0.08);

    /* Secondary text — pure white, same as body / headings.
       Operator directive (Session 11): every "secondary" text node (labels,
       "Total" in the allocation sidebar, "USD value · months 0–N" caption,
       lead paragraphs on every reference page) should read the same pure
       white as the headings. Visual hierarchy comes from font-size
       (`small`), font-weight, and layout — NOT from text-color dimming.

       CRITICAL: there are TWO different Bootstrap tokens here and they go
       to different utility classes. Both must be set, or one set of
       elements stays gray:

         `.text-secondary`     reads  --bs-secondary-rgb        (NO hex form;
                                                                  rgb-only;
                                                                  defined at
                                                                  :root, NOT in
                                                                  the dark-theme
                                                                  block by default)
         `.text-body-secondary` reads --bs-secondary-color      (hex)
         `.text-muted` (legacy) reads --bs-secondary-color      (alias)

       Earlier passes set --bs-secondary-color + --bs-secondary-color-rgb
       and assumed both utility classes picked them up. Wrong: .text-secondary
       reads --bs-secondary-rgb specifically (Bootstrap's BRAND secondary
       gray, default `108, 117, 125` = #6c757d). That's why the operator
       kept reporting "text secondary still gray" through three deploys —
       the actual token driving .text-secondary was untouched.

       Override BOTH families to white now:
         --bs-secondary-rgb       → .text-secondary white
         --bs-secondary-color     → .text-body-secondary white
         --bs-secondary-color-rgb → kept in sync for any utility class
                                    that may read it (e.g. .text-body-emphasis
                                    via inherited tokens; cheap to set).

       Tertiary (placeholder text, disabled hints) keeps a step at
       gray-400 / gray-500 so genuinely-subordinate affordances remain
       visibly secondary. */
    --bs-secondary-rgb: 255, 255, 255;
    --bs-secondary-color: #ffffff;
    --bs-secondary-color-rgb: 255, 255, 255;
    --bs-tertiary-color: #ced4da;
    --bs-tertiary-color-rgb: 206, 212, 218;
}

/* Pure-white headings with slightly tightened letter spacing — the
   off-white default read as muted on the deeper body background. */
h1, .h1, h2, .h2, h3, .h3, h4, .h4 {
    color: #ffffff;
    letter-spacing: -0.01em;
}

/* The Navbar gets a darker tone than the rest of the page so the
   page body and the chrome (navbar + accent ribbon) read as two
   distinct strata. */
.navbar {
    background-color: var(--yieldsim-bg-deep);
    border-bottom: none !important;
}

/* Page-accent ribbon. 3px gradient stripe right under the navbar.
   2026-05-27 revision 2: was a tri-colour chart-coded gradient
   (XRP-blue / USD-green / hybrid-yellow) showing the three strategy
   categories — operator pulled it into chrome too so the navbar reads
   as a single brand voice. Chart color-coding still lives on the chart,
   assumption-card accent stripes, and tier badges; the ribbon no longer
   duplicates that legend.
   Single-hue blood-red sweep: deep at the edges, bright in the centre.
   Reads like ink bleeding across the navbar's lower edge rather than a
   flat line, while staying entirely inside the chrome ramp. */
.page-accent-ribbon {
    height: 3px;
    background: linear-gradient(to right,
        var(--yieldsim-chrome-deep)   0%,
        var(--yieldsim-chrome)       25%,
        var(--yieldsim-chrome-bright) 50%,
        var(--yieldsim-chrome)       75%,
        var(--yieldsim-chrome-deep) 100%);
}

/* Navbar slogan — alliteration treatment (Session 11 close).
   Reads: "What's profitable is a picture of what's possible, then probable,
   then prudent." The four P-words carry the alliteration; the body of the
   line is set in an italic serif to give the slogan an editorial / aphoristic
   feel (vs the sans-serif of the rest of the UI), and each P-word breaks the
   italic flow with an upright bold accent so the P's punctuate the line
   visually as well as phonetically.

   Type stack: Georgia first, then web-safe serif fallbacks. No webfont
   download — Georgia ships with Windows / macOS / iOS, "Liberation Serif"
   covers most Linux distros, and the generic `serif` keyword catches the
   rest. Latency-free, no FOIT, no CDN dependency. */
.navbar-slogan {
    background-color: transparent;
    color: #ffffff;
    font-family: Georgia, "Times New Roman", "Liberation Serif", serif;
    font-style: italic;
    font-weight: 400;
    font-size: 0.95rem;
    letter-spacing: 0.015em;
    line-height: 1.35;
    border: none;
    /* Cap width so the longer slogan doesn't push the navbar around at
       md+ widths. With the Session 11 expansion to a 7-P alliteration
       ("Profitable / Portfolio / Projection / Picture / Possible / Probable
       / Prudent") the line wants ~52rem to render on one row at lg+; below
       that it wraps to two rows, which the navbar absorbs vertically. At
       xs/sm the navbar is already collapsed (mobile menu), so the slogan
       only renders inline starting at lg. */
    max-width: 52rem;
    text-align: right;
}

/* The seven P-words: "Profitable / Portfolio / Projection / Picture /
   Possible / Probable / Prudent". Break the surrounding italic with an
   upright bold cut + chrome-oxblood accent so the alliteration registers
   visually at glance distance. The slight letter-spacing tightens the bold
   weight back to roughly the optical density of the italic body around it.
   (Was XRP-blue prior to the 2026-05-27 palette pivot — see the chrome
   palette comment block at the top of this file.) */
.slogan-accent {
    /* Thin text — use BRIGHT step per chrome usage rule. Base #8b0000 is
       too low-luminance for thin bold text on near-black to read at glance
       distance. */
    color: var(--yieldsim-chrome-bright);
    font-style: normal;
    font-weight: 700;
    letter-spacing: 0.005em;
}

/* Leading capital P of each P-word — the alliteration anchor. Three-tier
   typographic hierarchy is intentional:
     • Body of the slogan        : italic, regular,  white               (.navbar-slogan)
     • Body of each P-word       : upright, bold,    oxblood             (.slogan-accent)
     • Leading P of each P-word  : italic,  bold,    bright oxblood 1.2em (.slogan-p)
   The leading P echoes the italic flourish of the surrounding sentence
   (visually tying it back to the body line) while staying clearly the
   tallest, brightest element in the slogan. The `display: inline-block` +
   slight negative `margin-right` keeps the larger P snug against its
   following lowercase letters instead of leaving a perceptual gap.
   `line-height: 0` prevents the bigger P from inflating the navbar height. */
.slogan-p {
    /* One step brighter than .slogan-accent so the leading P pops above
       the P-word body, same way the prior #74c0fc popped above #4dabf7.
       .slogan-accent now uses chrome-bright (#b30000) so the leading P
       jumps to #d40000 — pure red, even more vivid, one step up. */
    color: #d40000;
    font-style: italic;
    font-weight: 700;
    font-size: 1.2em;
    line-height: 0;
    letter-spacing: 0;
    display: inline-block;
    margin-right: -0.02em;
    /* Tiny baseline lift so the larger P sits visually centred against the
       lowercase letters that follow — without this it appears to "drop" a
       few pixels below the lowercase baseline because of its extra height. */
    vertical-align: -0.02em;
}

/* Brand wordmark sits next to the logo at the navbar's left edge.
   Bumped from default to a slightly larger size so the brand reads
   from across the page. */
.navbar-brand {
    font-size: 1.35rem;
}

/* Nav links: clearer at-rest contrast, white on hover, accent when
   the current page is active. Active state is set via aria-current
   in Razor / Bootstrap conventions; we also hook the bare hover. */
.navbar-nav .nav-link {
    color: #ced4da;
    transition: color 0.15s ease-in-out;
}
.navbar-nav .nav-link:hover,
.navbar-nav .nav-link:focus-visible {
    color: #ffffff;
}
.navbar-nav .nav-link.active,
.navbar-nav .nav-link[aria-current="page"] {
    /* Active-page link is chrome, not chart-coding — paint with brand
       blood-red. Uses BRIGHT step per chrome usage rule: thin text on
       near-black needs the higher-luminance variant or the active state
       reads as just-dim instead of red. (Was XRP-blue prior to the
       2026-05-27 palette pivot.) */
    color: var(--yieldsim-chrome-bright);
    font-weight: 600;
}

/* Brand wordmark "Yield" — the .text-info span in _Layout.cshtml carries
   .brand-yield in addition, to compensate for the Stevens chromatic-
   luminance effect: deep blood-red letterforms against bright-white "Sim"
   on near-black get perceptually thinned (the eye reads them as smaller
   even though geometric font-size is identical). Two compensations:
     1. font-weight bump (600 vs the wordmark's default 400) — adds
        ink-weight so the strokes match the visual density of "Sim"
     2. Paint with chrome-bright (#b30000), not chrome — Bootstrap's
        .text-info already inherits --bs-info which is set to chrome-bright
        at the top of this file, but stating it explicitly here keeps the
        rule legible at the call-site even if the token mapping shifts.
   Specificity note: .brand-yield is at single-class rank, same as
   .text-info. The Bootstrap utility carries !important on `color`, so we
   echo !important here to win the cascade tie. */
.brand-yield {
    color: var(--yieldsim-chrome-bright) !important;
    font-weight: 600;
}

/* Cards: stronger shadow + subtle top-edge highlight so they read as
   raised tiles against the deeper body background. The shadow uses
   pure-black at low alpha so it doesn't tint the card edge in any
   accent direction. We also override the Bootstrap body-tertiary token's
   default (which is too close to the page bg in dark theme) with our
   own --yieldsim-bg-card so every .card.bg-body-tertiary on the page
   reads as an elevated tile, not a flat region of the body. */
.card.bg-body-tertiary {
    background-color: var(--yieldsim-bg-card) !important;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
    border: 1px solid rgba(255, 255, 255, 0.06) !important;
}

/* Form-control / form-select / input-group surface — sits ABOVE the
   parent card so fields are visibly editable (the prior `bg-body` class
   on inputs inside body-tertiary cards meant inputs read as transparent
   patches of the page, and the field boundary disappeared). Applies to
   the explicit `bg-body` utility (which the dashboard uses to opt into
   the prior look) AND to bare form-controls so any future input gets
   the same surface without needing the class. */
.form-control,
.form-select,
.form-control.bg-body,
.form-select.bg-body,
.input-group .form-control.bg-body {
    background-color: var(--yieldsim-bg-input) !important;
    border-color: rgba(255, 255, 255, 0.08);
    color: var(--bs-body-color);
}
.form-control:disabled,
.form-select:disabled {
    background-color: var(--yieldsim-bg-card) !important;
    opacity: 0.65;
}
/* Input-group addons (`$`, `%`, etc.) — match the input surface so the
   prefix/suffix reads as one continuous field rather than two tiles. */
.input-group-text {
    background-color: var(--yieldsim-bg-input);
    border-color: rgba(255, 255, 255, 0.08);
    color: var(--bs-secondary-color);
}

/* Primary button — remap Bootstrap's default (a desaturated indigo
   under dark theme) to chrome blood-red so the "Run simulation" CTA reads
   as the primary action on the dashboard.
   Text-color rule: prior pass used near-black-on-azure (#4dabf7 is bright
   enough to take dark text). Chrome blood-red #8b0000 fails contrast
   against dark text (~1.9:1) and clears AAA against pure white (~9.0:1) —
   so this button MUST keep white text. Same rule applies to every other
   chrome-tinted CTA below. */
.btn-primary {
    background-color: var(--yieldsim-chrome);
    border-color: var(--yieldsim-chrome);
    color: #ffffff;
    font-weight: 600;
}
.btn-primary:hover,
.btn-primary:focus-visible,
.btn-primary:active {
    background-color: var(--yieldsim-chrome-bright);
    border-color: var(--yieldsim-chrome-bright);
    color: #ffffff;
}

/* Outline-info buttons: brighter border + bolder font so secondary
   actions ("Edit this assumption", modal triggers) don't fade.
   (Bootstrap's --bs-info family is already remapped to chrome oxblood in
   the [data-bs-theme] block above, so referring to the chrome var here
   keeps the rule self-documenting at the call-site.) */
.btn-outline-info {
    border-color: var(--yieldsim-chrome);
    color: var(--yieldsim-chrome-bright); /* a step brighter than the border so the label clears contrast on bg-page */
    font-weight: 500;
}
.btn-outline-info:hover,
.btn-outline-info:focus-visible {
    background-color: var(--yieldsim-chrome);
    border-color: var(--yieldsim-chrome);
    color: #ffffff;
}

/* Filled .btn-info (Save override, view-mode toggle on /assumptions) gets
   the same chrome treatment as .btn-primary — both surfaces are "commit
   the chrome action," and styling them identically prevents the toggle
   from reading as a different action class than the rest of the chrome
   CTAs. Added 2026-05-27 alongside the palette pivot — previously these
   buttons inherited Bootstrap's default cyan info, which clashed with the
   new oxblood chrome. */
.btn-info {
    background-color: var(--yieldsim-chrome);
    border-color: var(--yieldsim-chrome);
    color: #ffffff;
    font-weight: 500;
}
.btn-info:hover,
.btn-info:focus-visible,
.btn-info:active {
    background-color: var(--yieldsim-chrome-bright);
    border-color: var(--yieldsim-chrome-bright);
    color: #ffffff;
}

/* Form input + select focus: chrome-coloured ring instead of
   Bootstrap's default desaturated glow.
   Halo rgb (139, 0, 0) matches --yieldsim-chrome (#8b0000) — kept literal
   here because rgba() can't dissect a CSS custom property. If the chrome
   hex ever changes, update both. */
.form-control:focus,
.form-select:focus {
    border-color: var(--yieldsim-chrome-bright); /* thin border line — bright step for visibility */
    box-shadow: 0 0 0 0.2rem rgba(139, 0, 0, 0.30);
}

/* (The .dashboard-header card wrapper was retired in the Session of
   2026-05-25 visual pass — the operator directive was "the Dashboard
   header should not be INSIDE of a section, it should be outside like all
   the other pages." The H1 + run-controls now sit bare on the page using
   the same `<div class="mb-3"><h1 class="h3 mb-1">` convention as every
   other page; no special rule needed for that vocabulary.) */

/* (The early-file .tier-badge override block was removed alongside the
   ProbabilityTier-→-Frequency/Severity refactor. The canonical badge
   geometry now lives in the .freq-badge / .sev-badge / .tier-badge rules
   below in this file, together with the new --yieldsim-freq-* and
   --yieldsim-sev-* palette ramps declared in :root.) */

/* Allocation rows: subtle separator between legs so the eye scans
   the sidebar as a list rather than a wall of inputs. */
.allocation-row + .allocation-row {
    border-top: 1px solid var(--bs-border-color-translucent);
    padding-top: 0.75rem;
}

/* Slightly tighter navbar padding so the disclaimer ribbon sits closer
   to the brand. */
.navbar {
    padding-top: 0.6rem;
    padding-bottom: 0.6rem;
}

/* Coming-soon stub styling — used on every page that doesn't have its
   real content yet. Picked to be visually obviously placeholder, not
   accidentally real UI. */
.coming-soon {
    border: 1px dashed var(--bs-border-color);
    padding: 2rem;
    text-align: center;
    color: var(--bs-secondary-color);
    background-color: var(--bs-tertiary-bg);
    border-radius: 0.5rem;
}

.coming-soon h2 {
    color: var(--bs-body-color);
    margin-bottom: 0.5rem;
}

/* Modal tweaks: generous padding per CLAUDE.md UI rules, ESC handled by
   Bootstrap default. */
.modal .modal-body {
    padding: 1.5rem;
}

/*
   Click-modal tooltip icon (the ⓘ next to every number / parameter on the
   dashboard). The icon must:
     - Be unobtrusive at rest (it's everywhere; if it shouts, the UI shouts).
     - Be clearly clickable on hover (cursor + brightened colour).
     - Be keyboard-focusable (it's a <button>, so focus-visible just works).
     - Not disrupt the surrounding text baseline (inline-baseline alignment,
       no vertical padding that pushes neighbour text around).
   No hover-only tooltip-text — Bootstrap's modal IS the tooltip per the
   UI rules in CLAUDE.md.
*/
.info-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    margin-left: 0.25rem;
    border: none;
    background: transparent;
    color: var(--bs-secondary-color);
    font-size: 0.9em;
    line-height: 1;
    cursor: pointer;
    transition: color 0.12s ease-in-out;
    vertical-align: baseline;
}

.info-icon-btn:hover,
.info-icon-btn:focus-visible {
    /* Hover/focus picks up chrome oxblood — the ⓘ glyph briefly previews
       the same accent the modal it opens will paint its CTAs with. */
    color: var(--yieldsim-chrome-bright);
    outline: none;
}

.info-icon-btn:focus-visible {
    /* Visible focus ring without breaking the dark-theme aesthetic. RGB
       (179, 0, 0) matches --yieldsim-chrome-bright (blood red) — uses the
       bright step because the surrounding hover .color also reads bright,
       keeping the focus halo and the icon-color in the same hue step. */
    box-shadow: 0 0 0 0.15rem rgba(179, 0, 0, 0.4);
    border-radius: 0.15rem;
}

/* ── Two-axis scenario badges ──────────────────────────────────────────
   Replaces the old single .tier-badge.{probable,plausible,extreme} set.
   Two distinct base classes (.freq-badge, .sev-badge) so a page rendering
   BOTH badges next to a scenario name signals two dimensions, not two
   instances of the same dimension. Shared geometry (padding, radius,
   weight) keeps the visual rhythm but the colours come from separate
   ramps (see --yieldsim-freq-* and --yieldsim-sev-* custom properties).

   Why two classes instead of one .scenario-badge with modifier suffixes:
   the click-modal tooltip's `TierClass` helper in _InfoTooltipModal.cshtml
   reads cleaner when each axis owns its own classname space — and CSS
   inheritance lets us share the geometry rules without forcing every
   call site to spell both classes together. */
.freq-badge,
.sev-badge {
    display: inline-block;
    padding: 0.15rem 0.5rem;
    font-size: 0.75rem;
    font-weight: 600;
    border-radius: 0.25rem;
    color: #1a1a1a;
}

/* Frequency axis — green/yellow/red traffic-light ramp. */
.freq-badge.routine  { background-color: var(--yieldsim-freq-routine); }
.freq-badge.episodic { background-color: var(--yieldsim-freq-episodic); }
.freq-badge.rare     { background-color: var(--yieldsim-freq-rare); }

/* Severity axis — teal/amber/magenta-red, rotated from the frequency
   ramp so two adjacent badges read as two dimensions instead of one
   duplicated label. */
.sev-badge.mild         { background-color: var(--yieldsim-sev-mild); }
.sev-badge.significant  { background-color: var(--yieldsim-sev-significant); }
.sev-badge.catastrophic { background-color: var(--yieldsim-sev-catastrophic); }

/* ── Strategy risk-profile badges ──────────────────────────────────────
   Per-strategy badges rendered alongside each strategy on the dashboard
   summary table and the Classroom Strategies cards. Four dimensions
   (Price / Counterparty / Smart-contract / Liquidity), each with a
   four-level rating (None / Low / Medium / High). Cluster of four
   small pill badges per strategy so the user can scan "where does this
   strategy carry which kind of risk" at a glance — pair with the
   per-assumption impact markers (🟢/🟡/🔴 sensitivity, not risk) to reason
   about which knobs amplify which risk.

   .risk-badge is the base shape (tighter padding than scenario badges
   because there are 4 per strategy and they need to fit a table row).
   Level modifier classes pull from the --yieldsim-risk-* ramp. */
.risk-badge {
    display: inline-block;
    padding: 0.08rem 0.4rem;
    margin-right: 0.2rem;
    font-size: 0.7rem;
    font-weight: 600;
    border-radius: 0.2rem;
    color: #ffffff;
    letter-spacing: 0.01em;
}

.risk-badge.level-none   { background-color: var(--yieldsim-risk-none); color: #adb5bd; }
.risk-badge.level-low    { background-color: var(--yieldsim-risk-low);  color: #08243d; }
.risk-badge.level-medium { background-color: var(--yieldsim-risk-medium); color: #ffffff; }
.risk-badge.level-high   { background-color: var(--yieldsim-risk-high); color: #3a0a1f; }

/* Cluster wrapper — used wherever the 4-axis cluster renders. Flex layout
   keeps the four pills on one line; allow-wrap so a very narrow viewport
   doesn't force overflow. */
.risk-cluster {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 0.15rem;
    align-items: center;
}

/* ── Upside ↔ risk trade-off frame ─────────────────────────────────────
   The teaching banner above the dashboard summary table plus the two
   column "pole" eyebrows. Added 2026-05-28 to make the core principle —
   "is the upside worth the risk?" — explicit in the design, not just the
   copy. The frame is a quiet inset strip (intentionally NOT a loud accent:
   it's guidance, not a warning), sitting on top of the card's
   bg-body-tertiary surface. The poles are tiny uppercase eyebrows coloured
   green (upside) / red (risk) so the eye reads the Return column and the
   Risk column as the two ends of a single trade. Kept subtle so it informs
   without competing with the chart for attention. */
.upside-risk-frame {
    background-color: rgba(255, 255, 255, 0.035);
    border: 1px solid rgba(255, 255, 255, 0.08);
}

.trade-pole {
    font-size: 0.6rem;
    letter-spacing: 0.05em;
    margin-bottom: 0.1rem;
    line-height: 1.1;
}

/* Legacy alias — anywhere still painting .tier-badge resolves to the
   frequency-axis colour ramp (closest semantic match — frequency was
   what the old "probability tier" mostly tried to communicate). Marked
   deprecated; new code should pick .freq-badge or .sev-badge directly. */
.tier-badge {
    display: inline-block;
    padding: 0.15rem 0.5rem;
    font-size: 0.75rem;
    font-weight: 600;
    border-radius: 0.25rem;
    color: #1a1a1a;
}
.tier-badge.probable  { background-color: var(--yieldsim-freq-routine); }
.tier-badge.plausible { background-color: var(--yieldsim-freq-episodic); }
.tier-badge.extreme   { background-color: var(--yieldsim-freq-rare); }
/* New-vocabulary aliases on the legacy class so anything painting
   .tier-badge with the new names also lands correctly. */
.tier-badge.routine        { background-color: var(--yieldsim-freq-routine); }
.tier-badge.episodic       { background-color: var(--yieldsim-freq-episodic); }
.tier-badge.rare           { background-color: var(--yieldsim-freq-rare); }
.tier-badge.mild           { background-color: var(--yieldsim-sev-mild); }
.tier-badge.significant    { background-color: var(--yieldsim-sev-significant); }
.tier-badge.catastrophic   { background-color: var(--yieldsim-sev-catastrophic); }

/*
   /assumptions page.

   The page renders one strategy card per StrategyKind that has at least
   one tunable assumption (grouped view) or a single flat A–Z list (flat
   view). Cards carry an accent stripe colour-coded by StrategyCategory
   (XRP / USD / hybrid), so a user who has spent time on the dashboard
   recognises which family each card belongs to without re-reading the
   heading. The accent colour is passed in via the --assumption-accent
   custom property set inline per card by the Razor view.

   Rows inside a card are stacked with a thin separator so the eye can
   scan from one definition to the next without losing place.
*/
.assumption-card {
    /* Left-edge accent stripe that picks up the per-category colour. The
       inset is purely cosmetic — the card body keeps its own padding. */
    border-left: 0.25rem solid var(--assumption-accent, var(--bs-border-color)) !important;
}

.assumption-card-accent {
    /* Small filled square next to the strategy heading. Mirrors the colour
       swatches used in the dashboard's allocation sidebar and summary table
       so the visual vocabulary stays consistent across pages. */
    display: inline-block;
    width: 0.65rem;
    height: 0.65rem;
    border-radius: 0.15rem;
    background-color: var(--assumption-accent, var(--bs-border-color));
    margin-right: 0.4rem;
    vertical-align: 0.05em;
}

.assumption-row {
    /* Subtle separator between rows in the vstack. Inherits the card's
       background; the border is the only visual divider so the eye can
       still parse adjacent rows as a continuous list. */
    padding-bottom: 0.85rem;
    border-bottom: 1px solid var(--bs-border-color-translucent);
}

.assumption-row:last-child {
    /* The last row inside a card doesn't need a divider — the card edge
       already terminates the visual list. */
    padding-bottom: 0;
    border-bottom: none;
}

.assumption-row:target {
    /* When the page is reached via /assumptions#asm-hysa-apr the target
       row briefly highlights so the user sees where the deep link landed.
       Subtle box-shadow rather than a background flash — non-intrusive
       and works against the dark theme. Halo color follows chrome blood-red
       (was XRP-blue prior to the 2026-05-27 palette pivot); uses the
       BRIGHT step because the highlight needs to register at glance
       distance — base #8b0000 would feel like a dim shadow against the
       dark row. RGB (179, 0, 0) is --yieldsim-chrome-bright decomposed. */
    box-shadow: 0 0 0 2px var(--yieldsim-chrome-bright), 0 0 12px rgba(179, 0, 0, 0.45);
    border-radius: 0.25rem;
    padding: 0.5rem 0.75rem 0.85rem;
    /* Smooth-in so the highlight doesn't feel jumpy on first paint. */
    transition: box-shadow 0.25s ease-in-out, padding 0.25s ease-in-out;
}

/* Session-override visual cue on the row. A subtle
   left-edge accent (warning-yellow, matching the "overridden" badge) so a
   user scanning /assumptions for "what did I change" can spot overridden
   rows in peripheral vision without reading the value badges. Paired with
   the badge + reset-button in markup so the cue is redundant-with-text,
   not the only signal (accessibility — colour-blind users still see the
   badge). */
.assumption-row-overridden {
    border-left: 3px solid var(--bs-warning);
    padding-left: 0.75rem;
    margin-left: -0.75rem;
}

/* ─────────────────────────────────────────────────────────────────────
   Run-simulation CTA. Earlier attempts (glassy + neon, uppercase +
   tracking, oversized, lightning bolt) read as goofy + disconnected
   from the rest of the form. Reset to a confident-but-restrained
   primary button: same Bootstrap size as the other form inputs, brand
   chrome oxblood base with a subtle gradient, hover gives a satisfying
   warm-up via brightness + glow (no scale, no transform — those
   read as gimmicky when the user only wants to commit a value).

   No icon. No uppercase. Just a button that earns its space by
   feeling deliberate when you mouse it. Palette: chrome-bright on top,
   chrome on bottom — keeps the same "top brighter than bottom" depth
   cue the prior XRP-blue gradient had, just rotated to the new hue.
   ───────────────────────────────────────────────────────────────── */
.btn-run-simulation {
    /* Chrome blood-red gradient — top stop is the bright step, bottom is
       the base, giving a tiny sense of depth without a heavy shadow. */
    background: linear-gradient(180deg, var(--yieldsim-chrome-bright) 0%, var(--yieldsim-chrome) 100%);
    border: 1px solid var(--yieldsim-chrome);
    /* White label clears AAA against both gradient stops (~9.0:1 on
       #8b0000, ~7.4:1 on #b30000). Prior near-black-on-azure pattern
       fails on these hues — see the chrome palette comment block at the
       top of this file. */
    color: #ffffff;

    font-weight: 600;
    /* Match the form-select-sm height so the button doesn't look
       oversized next to Capital / Horizon / Scenario. */

    transition:
        background 160ms ease,
        border-color 160ms ease,
        box-shadow 160ms ease;
}

.btn-run-simulation:hover,
.btn-run-simulation:focus-visible {
    /* Hover stays inside the same single-hue blood-red ramp — brightens
       both stops one step. Outer halo uses rgb(179, 0, 0) =
       --yieldsim-chrome-bright; inner ring uses an even brighter pure red
       (#d40000 = 212, 0, 0) so the focus halo carries a perceptible step
       above the button surface. rgba() can't dissect a CSS custom property
       which is why the rgb triplets are spelled out. */
    background: linear-gradient(180deg, var(--yieldsim-chrome-bright) 0%, var(--yieldsim-chrome-bright) 100%);
    border-color: var(--yieldsim-chrome-bright);
    color: #ffffff;
    box-shadow: 0 0 0 1px rgba(212, 0, 0, 0.5), 0 0 10px rgba(179, 0, 0, 0.5);
    outline: none;
}

.btn-run-simulation:active {
    /* Pressed state drops to the deeper of the three palette stops so the
       button visibly settles in when committed. rgb(92, 0, 0) decomposes
       --yieldsim-chrome-deep (#5c0000). */
    background: linear-gradient(180deg, var(--yieldsim-chrome) 0%, var(--yieldsim-chrome-deep) 100%);
    box-shadow: 0 0 0 1px rgba(92, 0, 0, 0.6);
}

/* ─────────────────────────────────────────────────────────────────────
   Run-simulation WebGL glow scaffolding.

   .run-simulation-wrap wraps the button + canvas pair on the dashboard
   (Views/Home/Index.cshtml). The wrap is positioned so the absolute-
   positioned canvas can extend past the button bounds without affecting
   the surrounding Bootstrap grid layout — the form column still measures
   exactly the button's width, but the canvas (inset: -22px) bleeds 22px
   past each edge so the plasma glow can fade out beyond the button.

   The canvas is purely decorative — pointer-events:none so it never
   intercepts the button's click target, aria-hidden in markup so screen
   readers skip it. WebGL shader + animation loop lives in
   /js/run-button-glow.js (loaded from the @section Scripts block on
   Index.cshtml). If WebGL isn't available the JS module hides the canvas
   and falls back to the base .btn-run-simulation styling alone — the
   gradient + hover halo there give a complete look on their own, so the
   no-effect fallback still feels intentional.
   ───────────────────────────────────────────────────────────────── */
.run-simulation-wrap {
    /* The button still wants w-100 inside the col-md-2 grid cell, so the
       wrapper is display:block and the button's own width:100% takes
       effect inside it. position:relative establishes the containing
       block for the absolutely-positioned canvas. */
    position: relative;
    display: block;
}

#run-glow-canvas {
    /* Canvas extends 30px past each button edge so the plasma glow has
       room to fade smoothly to zero before hitting the rectangular
       canvas border. The shader fade-mask (run-button-glow.js) reaches
       0 exactly at the canvas edge — but the perceived smoothness of
       the fade depends on having enough pixels between the button
       perimeter and the canvas edge for the gradient to spread over.
       At -22px (the original inset) the vertical fade only had ~6px
       of room past the button top/bottom, which read as too abrupt;
       -30px nearly doubles that. Bumped 2026-05-27 alongside the
       shader fade-mask rewrite — operator caught the box outline.
       The button itself sits at z-index:1 to float above the canvas;
       default position:static would leave the canvas on top, hiding
       the button. pointer-events:none routes clicks through to the
       button beneath. */
    position: absolute;
    inset: -30px;
    width: calc(100% + 60px);
    height: calc(100% + 60px);
    pointer-events: none;
    z-index: 0;
    /* CSS sizing is what the JS reads via getBoundingClientRect() — the
       backing-store resolution gets multiplied by devicePixelRatio in
       run-button-glow.js so HiDPI displays render the plasma sharply. */
}

/* Button needs an explicit z-index so it stacks above the canvas inside
   the wrap. Applied via the wrap descendant selector so this rule only
   fires for the run-sim button in its WebGL-glow context and doesn't
   affect btn-run-simulation buttons in other layouts (if any are ever
   added). */
.run-simulation-wrap .btn-run-simulation {
    position: relative;
    z-index: 1;
}

/* ─────────────────────────────────────────────────────────────────────
   Custom-scenario builder: transient inline feedback for the
   "Linearly interpolate between first and last" button when the click
   is a no-op (first == last). JS toggles the `.is-visible` class for
   ~3 seconds. Styled as a muted warning so it reads as information,
   not error.
   ───────────────────────────────────────────────────────────────── */
.path-interpolate-feedback {
    display: inline-block;
    margin-left: 0.5rem;
    color: var(--bs-warning-text-emphasis, #ffc107);
    opacity: 0;
    transition: opacity 200ms ease;
    pointer-events: none;
}
.path-interpolate-feedback.is-visible {
    opacity: 1;
}
