/* Shared across all journal pages. Page-specific overrides belong in that
   page's {% block extra_css %}, not here. */

/* ============================================================
   PALETTE OPTIONS -- saved for later reference. Four candidates were
   mocked up (see conversation from 2026-08-05); "Sage & Chalk" is ACTIVE
   below (tried Sage Fog and Deep Sage first, both rejected). To switch,
   replace the :root block's values with one of these.

   Sage & Chalk, original sage (superseded by Olive & Brass below -- kept
   here in case this gets revisited):
     bg:#f5f7f4 surface:#ffffff text:#2b2f29 muted:#767d72 border:#e1e6dd
     sage:#5f8a63 sage-dark:#47694b sage-light:#91bc95 sage-subtle:#e9f1ea sage-emphasis:#3f5a40
     clay:#b3665f clay-dark:#954841 clay-subtle:#f6e5e3 clay-emphasis:#733934
     ochre:#c39a35 ochre-dark:#9d7828 ochre-subtle:#f7f0dc ochre-emphasis:#785a21

   Olive & Brass -- ACTIVE, see :root below for the full derived set.
   Warmer/earthier than the original sage (shifted off a cool minty green
   toward a muted olive) -- trialled page-scoped on Trade Dashboard's New
   Trade button + LIVE/SIM toggle first, then promoted here once it held up.
   Derived tiers (dark/emphasis/border-subtle) keep the same HSL deltas from
   base that the original sage tiers had, so the same relationships
   (hover = dark, text-on-subtle = emphasis, etc.) still hold:
     sage:#697C3C sage-dark:#475723 sage-light:#A1B474 sage-subtle:#F0F3E7 sage-emphasis:#3D461D
     primary/success-border-subtle:#E0E4CF

   Sage Fog (full green world -- tried, felt too flat/muddy):
     bg:#e7ede4 surface:#fbfdf9 text:#26302a muted:#64705f border:#cfd9c8
     sage:#4f7a56 sage-dark:#3c5f42 sage-light:#81ac88 sage-subtle:#edf4ea sage-emphasis:#2f4a33
     clay:#ab6a63 clay-dark:#8d4c45 clay-subtle:#f3e4e1 clay-emphasis:#6b3d38
     ochre:#b89434 ochre-dark:#927227 ochre-subtle:#f2ecd8 ochre-emphasis:#6d5420

   Sage & Slate (cooler, faint blue-green stone backdrop -- not yet tried live):
     bg:#eef1f1 surface:#ffffff text:#262b2a muted:#707c7a border:#dde3e2
     sage:#4f8464 sage-dark:#3a6650 clay:#a8635f ochre:#ba9536

   Deep Sage (dark theme -- tried, rejected):
     bg:#1b211c surface:#262e27 text:#e9ede6 muted:#9caa96 border:#37402f
     sage:#7fae7c sage-dark:#3c5f42 sage-light:#a8d1a5 sage-subtle:#2e3a2c sage-emphasis:#a8d1a5
     clay:#c98077 clay-dark:#b8695f clay-subtle:#3a2b28 clay-emphasis:#d99a90
     ochre:#d3ac52 ochre-dark:#b8903f ochre-subtle:#3d3620 ochre-emphasis:#e0c076
     Note: Deep Sage also needs --bs-btn-color flipped to var(--color-bg) on
     .btn-primary (dark text on the brighter button fill) and hover/active
     states lightened instead of darkened -- see git history / the
     conversation from 2026-08-05 if reviving this one.
   ============================================================ */

/* "Sage & Chalk": the app's mission is helping traders stay calm and heal
   from bad habits/patterns, so the palette avoids the stock-app default of
   saturated blue chrome and alarm-red/green P&L. Green/red are recolored to
   muted sage/clay (softer, non-alarming) rather than desaturated to gray --
   still readably "good/bad" at a glance, just not shouting it. These are the
   exact tones already validated on the Intentions page's yes/both/no dots,
   reused here for consistency instead of inventing a second palette.

   Bootstrap 5.3's utility classes (text-*, bg-*, border-*, focus rings) read
   these custom properties live, so overriding them here retheme those
   automatically. .btn-primary/.btn-outline-primary do NOT -- Bootstrap bakes
   literal colors into their own --bs-btn-* variables per class -- so those
   are overridden explicitly further down. */
:root {
    /* Tells the browser which palette to use for chrome it renders itself,
       not through our CSS -- native <select> dropdown popups, the
       <input type="date"> calendar overlay, scrollbars. Without this, those
       stay light-rendered regardless of the page's own theme, which is why
       dropdown option text (already themed light via --bs-body-color, see
       below) was unreadable: light text landing on a native popup that
       assumed a light background because nothing told it otherwise. */
    color-scheme: light;

    /* "Sage & Chalk": crisp and bright rather than a full green world --
       true-white cards lifted off a cool, barely-there backdrop. */
    --color-bg: #f5f7f4;
    --color-surface: #ffffff;
    --color-text: #2b2f29;
    --color-text-muted: #767d72;
    --color-border: #e1e6dd;

    --color-sage: #697C3C;
    --color-sage-dark: #475723;
    --color-sage-light: #A1B474; /* readable on dark backgrounds, e.g. the LIVE account card */
    --color-sage-subtle: #F0F3E7;
    --color-sage-emphasis: #3D461D;
    /* RGB triplets, referenced by --bs-primary-rgb/--bs-focus-ring-color/etc
       below and by .btn-primary/.btn-outline-primary further down -- kept as
       their own token (not just inlined in each spot) so the [data-theme]
       blocks only need to override these three, not every place that reads
       them. */
    --color-sage-rgb: 105, 124, 60;
    --color-sage-dark-rgb: 71, 87, 35;
    --color-sage-emphasis-rgb: 61, 70, 29;

    --color-clay: #b3665f;
    --color-clay-dark: #954841;
    --color-clay-subtle: #f6e5e3;
    --color-clay-emphasis: #733934;
    /* Referenced by --bs-danger-rgb below, same reason --color-sage-rgb
       exists for --bs-success-rgb: Bootstrap's .text-danger/.bg-danger
       utilities read the *-rgb custom property (rgba(var(--bs-danger-rgb),
       opacity)), not --bs-danger directly, so without this --bs-danger-rgb
       had to be hardcoded to a literal RGB triplet that never changed
       between themes -- .text-danger stayed light theme's clay in every
       theme regardless of what --color-clay itself resolved to. */
    --color-clay-rgb: 179, 102, 95;

    --color-ochre: #c39a35;
    --color-ochre-dark: #9d7828;
    --color-ochre-subtle: #f7f0dc;
    --color-ochre-emphasis: #785a21;

    /* Two more, alongside sage/clay/ochre -- originally added locally on
       the Charts page for its mistake/mood/routine/rule categories (sage
       and clay already carry a fixed profit/loss meaning there), promoted
       here since the sidebar and Home page's "Today" cards need the same
       two hues for Action Plans/Pre-Market Routine identity. */
    --color-slate: #5b7a99;
    --color-slate-dark: #3f5972;
    --color-slate-subtle: #e8eef3;

    --color-plum: #8a6a83;
    --color-plum-dark: #6b4f66;
    --color-plum-subtle: #f1e9ef;

    /* Same promotion story as slate/plum above: gold/teal started as
       Action Plans' own page-local :root vars (its habit/skill spotlight
       cards, buttons, progress bar, vault groups all lean on them
       extensively), duplicated with slightly different hex values from
       what's already here (its gold was a near-duplicate of --color-ochre).
       Promoted so that page draws from the same shared palette as
       everything else instead of carrying its own parallel one.

       Tried retuning this hue away from ochre (41deg->34deg) to fix that
       near-duplicate -- reverted, it read as orange rather than gold. Left
       matching ochre for now; a smaller/subtler shift might thread the
       needle better if this gets revisited. */
    --color-gold: #C89B3C;
    --color-gold-dark: #8C6816;
    --color-gold-subtle: #F1E3BE;

    --color-teal: #2E9187;
    --color-teal-dark: #1B6E67;
    --color-teal-subtle: #DCEEEA;

    --color-neutral-subtle: #edefe9;

    /* Routine's completion heatmap -- a graduated same-hue ramp, kept as
       its own tokens since a 4-5 step scale doesn't fit the base/dark/
       subtle 3-tier pattern the rest of the palette uses. rlvl-1..3 were
       hardcoded literals that never got a dark-theme counterpart when the
       rest of the app was tokenized; in dark themes that meant 3 of 5
       steps rendered as near-identical pale near-white dots, unreadable
       against a dark card.

       --color-heat-4 (the "fully completed" top step) equals --color-sage
       here -- unchanged from before, since rlvl-4 previously read
       var(--custom)/--color-sage directly and light theme wasn't reported
       broken. Given its own value in dark/deep-sage instead of continuing
       to alias sage there: reusing the muted button-sage token left rlvl-3
       and rlvl-4 at ~1:1 contrast (effectively the same color) once sage
       itself got desaturated for the eye-strain pass. Same fix as
       Intentions' heatmap dots -- a small chip can be more vivid than a
       full button surface without the vividness itself being the problem. */
    /* rlvl-1/2 (partial completion, still missing something) stay on the
       ochre/amber "warning" hue (--color-ochre is aliased to --bs-warning,
       and it's Intentions' heatmap color for a mixed Yes/No day) rather
       than green -- skipping even one item should visibly flag, not fade
       toward "basically done." rlvl-3 (one item short of fully completed)
       is the one exception: a lighter tint of rlvl-4's own hue rather than
       ochre, so the ramp still reads as one continuous gradient into
       "complete" at the very last step instead of a hard color-family cut
       right up against it. */
    --color-heat-1: #B3831F;
    --color-heat-2: #DCC077;
    --color-heat-3: #B4C78A;
    --color-heat-4: var(--color-sage);
    /* Was var(--color-clay-subtle) -- a pale background TINT meant to sit
       behind dark text on a light card, not a small solid-fill chip. It
       technically worked here (still a visible dusty pink against white),
       but in dark theme the same token measured ~1:1 contrast against the
       page, i.e. actually invisible. Landed on one coral value (below)
       that works as a real, clearly-"red" chip in all three themes rather
       than a different literal per theme. */
    --color-heat-miss: #E08076;

    /* Intentions' Both/No heatmap dots -- aliased to ochre/clay directly in
       light theme (identical to those tokens, no behavior change there),
       but given their own values in dark/deep-sage below. Reusing the
       plain ochre/clay tokens there left both at the same flattened
       saturation (part of the eye-strain recalibration), which made small
       dots read as "the same muted color at different brightness" instead
       of distinct hues. These need more saturation than the accent tokens
       can have globally -- boosting ochre/clay themselves back up would
       undo that recalibration everywhere else they're used (buttons,
       badges). Small isolated dots can afford more vividness than a full
       button surface without reintroducing the same fatigue. (Yes has no
       --color-heat-yes counterpart -- it intentionally uses plain
       --color-sage instead, to match the Pre-Market Routine page's
       fully-submitted color exactly; see intentions.html.) */
    --color-heat-both: var(--color-ochre);
    --color-heat-no: var(--color-clay);

    /* Trade grid's Grade badge (see .grade-badge in trade_dashboard.html) --
       aliased to the plain sage-emphasis/ochre-dark/clay-dark tokens here,
       identical to before (no behavior change in light theme). Given their
       own values in dark/deep-sage below instead: those same token names
       get redefined there as pale, low-saturation colors meant for
       readable TEXT on a dark page, not a small solid badge fill -- reused
       as-is they made A/B/D read as washed-out pastel green/tan/pink
       instead of a bold graded color. */
    --color-grade-a: var(--color-sage-emphasis);
    --color-grade-b: var(--color-ochre-dark);
    --color-grade-cd: var(--color-clay-dark);

    /* Flatpickr's selected/today-hover day fill (see FLATPICKR below) --
       plain var(--color-sage) here in light theme, same as everywhere else,
       since a dark-green fill with light text already reads clearly as
       "selected." Given its own value in dark/deep-sage instead: dark
       theme's --color-sage (#90A857) is a medium-brightness green, and
       pairing it with dark text (needed there for contrast -- white text
       only clears ~2.6:1 against it) read as a stray dark smudge inside the
       circle rather than an obviously-selected day. Same vivid green
       already used for the Grade-A badge fixes that: bright enough that
       dark text unambiguously looks intentional instead of like broken
       text color. */
    --color-picker-accent: var(--color-sage);

    --bs-primary: var(--color-sage);
    --bs-primary-rgb: var(--color-sage-rgb);
    --bs-primary-text-emphasis: var(--color-sage-emphasis);
    --bs-primary-bg-subtle: var(--color-sage-subtle);
    --bs-primary-border-subtle: #E0E4CF;

    --bs-success: var(--color-sage);
    --bs-success-rgb: var(--color-sage-rgb);
    --bs-success-text-emphasis: var(--color-sage-emphasis);
    --bs-success-bg-subtle: var(--color-sage-subtle);
    --bs-success-border-subtle: #E0E4CF;

    --bs-danger: var(--color-clay);
    --bs-danger-rgb: var(--color-clay-rgb);
    --bs-danger-text-emphasis: var(--color-clay-emphasis);
    --bs-danger-bg-subtle: var(--color-clay-subtle);
    --bs-danger-border-subtle: #e8cdc9;
    /* Bootstrap's own .form-control.is-invalid/.form-select.is-invalid
       (and TomSelect's matching .ts-wrapper.is-invalid, which bakes in the
       exact same two variables in its own vendor CSS) read these directly
       -- unlike --bs-danger above, they're never derived from it, so
       overriding --bs-danger alone left every invalid-field border/ring
       on Bootstrap's stock red (#dc3545) regardless of theme. */
    --bs-form-invalid-color: var(--color-clay);
    --bs-form-invalid-border-color: var(--color-clay);

    --bs-warning: var(--color-ochre);
    --bs-warning-rgb: 195, 154, 53;
    --bs-warning-text-emphasis: var(--color-ochre-emphasis);
    --bs-warning-bg-subtle: var(--color-ochre-subtle);
    --bs-warning-border-subtle: #e9dcb0;

    --bs-body-bg: var(--color-bg);
    --bs-body-color: var(--color-text);
    --bs-secondary-color: var(--color-text-muted);
    --bs-border-color: var(--color-border);
    --bs-link-color: var(--color-sage-dark);
    --bs-link-color-rgb: var(--color-sage-dark-rgb);
    --bs-link-hover-color: var(--color-sage-emphasis);
    --bs-link-hover-color-rgb: var(--color-sage-emphasis-rgb);
    --bs-focus-ring-color: rgba(var(--color-sage-rgb), 0.25);
}

/* ============================================================
   THEMES -- Light (above) is the default via :root. Dark and Deep Sage
   override just the neutral + accent tokens; every component reads them
   through var(), so nothing below this block needs theme-specific CSS.

   Recalibrated once already: the first pass brightened accents while
   keeping their light-theme saturation, and pushed neutrals close to
   true black/white (~12:1 text contrast). Both read as "vivid on near-
   black" -- technically passing contrast, but the combination is exactly
   what causes eye strain/halation in dark UIs. This version keeps accents
   muted (saturation cut, not boosted) while only lightening them enough
   that dark ink text (var(--color-bg)) still reads clearly on top, and
   dims the neutrals (~9:1 text contrast, dark bg lightened off true
   black) instead of maximizing contrast for its own sake. Every base/ink
   and emphasis/subtle pair still checked: all >=4.5:1. */
[data-theme="dark"] {
    color-scheme: dark;
    --color-bg: #1D2026;
    --color-surface: #262931;
    --color-text: #C7CAD1;
    --color-text-muted: #8B929C;
    --color-border: #393E46;
    --color-neutral-subtle: #30343B;

    --color-sage: #90A857;
    --color-sage-dark: #A3BA6F;
    --color-sage-light: #A3BA6F;
    --color-sage-subtle: #2F3423;
    --color-sage-emphasis: #BAC5A0;
    --color-sage-rgb: 144, 168, 87;
    --color-sage-dark-rgb: 163, 186, 111;
    --color-sage-emphasis-rgb: 186, 197, 160;

    --color-clay: #C79792;
    --color-clay-dark: #D7AFAB;
    --color-clay-subtle: #342423;
    --color-clay-emphasis: #E4D4D3;
    --color-clay-rgb: 199, 151, 146;

    --color-ochre: #BEAD81;
    --color-ochre-dark: #CEBF9A;
    --color-ochre-subtle: #342F23;
    --color-ochre-emphasis: #DDD7C8;

    --color-slate: #7F9EBD;
    --color-slate-dark: #97B2CD;
    --color-slate-subtle: #232B34;

    --color-plum: #BD7FAF;
    --color-plum-dark: #CD97C1;
    --color-plum-subtle: #342330;

    --color-gold: #C2B089;
    --color-gold-dark: #D2C3A2;
    --color-gold-subtle: #342E23;

    --color-teal: #5CABA3;
    --color-teal-dark: #73BCB4;
    --color-teal-subtle: #233432;

    /* rlvl-1/2 stay on the ochre "warning" hue, rlvl-3 is a lighter tint of
       rlvl-4's own hue instead -- see the long comment on the :root
       definition. Same hues as light theme, lightened for a dark card. */
    --color-heat-1: #C9973D;
    --color-heat-2: #E8CA8C;
    --color-heat-3: #95B54A;
    --color-heat-4: #6D8042;
    /* --color-heat-miss not overridden here -- same coral in every theme,
       see the :root definition. */

    --color-heat-both: #D8B764;
    --color-heat-no: #D37369;

    /* Bumped saturation well above --color-sage-emphasis/--color-ochre-dark/
       --color-clay-dark's own dark-theme values (which are pale, ~24-35%
       saturation -- tuned for on-dark-page text, not a solid badge fill)
       so A/B/D read as a confident graded color instead of a pastel chip.
       CD reuses --color-heat-miss, the same coral already established as
       this app's "this needs attention" red. */
    --color-grade-a: #8ACF59;
    --color-grade-b: #D4AE54;
    --color-grade-cd: var(--color-heat-miss);

    /* Same fix as --color-grade-a above -- see the :root definition's
       comment for why plain --color-sage doesn't work here. */
    --color-picker-accent: #8ACF59;

    --bs-primary-border-subtle: #535C3D;
    --bs-success-border-subtle: #535C3D;
}

[data-theme="deep-sage"] {
    color-scheme: dark;
    --color-bg: #20241E;
    --color-surface: #2A2F27;
    --color-text: #D3D4CE;
    --color-text-muted: #9B9F93;
    --color-border: #3C4338;
    --color-neutral-subtle: #363D33;

    --color-sage: #8EA35C;
    --color-sage-dark: #A2B573;
    --color-sage-light: #A2B573;
    --color-sage-subtle: #313527;
    --color-sage-emphasis: #B9C2A3;
    --color-sage-rgb: 142, 163, 92;
    --color-sage-dark-rgb: 162, 181, 115;
    --color-sage-emphasis-rgb: 185, 194, 163;

    --color-clay: #C49996;
    --color-clay-dark: #D4B1AE;
    --color-clay-subtle: #352827;
    --color-clay-emphasis: #E2D5D4;
    --color-clay-rgb: 196, 153, 150;

    --color-ochre: #BAAB85;
    --color-ochre-dark: #CBBE9D;
    --color-ochre-subtle: #353127;
    --color-ochre-emphasis: #DCD6CA;

    --color-slate: #829EB9;
    --color-slate-dark: #9AB2CA;
    --color-slate-subtle: #272E35;

    --color-plum: #B982AD;
    --color-plum-dark: #CA9AC0;
    --color-plum-subtle: #352732;

    --color-gold: #BFAF8D;
    --color-gold-dark: #CFC2A5;
    --color-gold-subtle: #353127;

    --color-teal: #61A69F;
    --color-teal-dark: #78B8B1;
    --color-teal-subtle: #273534;

    /* Same values as the dark theme above -- see the long comment on the
       :root definition. */
    --color-heat-1: #C9973D;
    --color-heat-2: #E8CA8C;
    --color-heat-3: #95B54A;
    --color-heat-4: #6D8042;
    /* --color-heat-miss not overridden here -- same coral in every theme,
       see the :root definition. */

    --color-heat-both: #D2B260;
    --color-heat-no: #CE6F64;

    /* Same fix as dark theme's --color-grade-* above -- see that comment. */
    --color-grade-a: #8ACF59;
    --color-grade-b: #D4AE54;
    --color-grade-cd: var(--color-heat-miss);
    --color-picker-accent: #8ACF59;

    --bs-primary-border-subtle: #525A3F;
    --bs-success-border-subtle: #525A3F;
}

/* --bs-btn-*-color default to Bootstrap's baked-in white, which only works
   because light theme's accent fills are dark enough for white text. Dark
   theme's fills are deliberately brightened (see the THEMES block above) so
   they read against a near-black page -- white text on top of those fails
   contrast, so text flips to var(--color-bg) instead: light theme's bg is
   near-white (matches the old hardcoded white), dark theme's bg is
   near-black (correct for the now-light fill). Self-corrects per theme
   without needing a theme-specific override here. */
.btn-primary {
    --bs-btn-color: var(--color-bg);
    --bs-btn-bg: var(--color-sage);
    --bs-btn-border-color: var(--color-sage);
    --bs-btn-hover-color: var(--color-bg);
    --bs-btn-hover-bg: var(--color-sage-dark);
    --bs-btn-hover-border-color: var(--color-sage-dark);
    --bs-btn-active-color: var(--color-bg);
    --bs-btn-active-bg: var(--color-sage-dark);
    --bs-btn-active-border-color: var(--color-sage-dark);
    --bs-btn-disabled-color: var(--color-bg);
    --bs-btn-disabled-bg: var(--color-sage);
    --bs-btn-disabled-border-color: var(--color-sage);
    --bs-btn-focus-shadow-rgb: var(--color-sage-rgb);
}

.btn-outline-primary {
    --bs-btn-color: var(--color-sage-dark);
    --bs-btn-border-color: var(--color-sage);
    --bs-btn-hover-color: var(--color-bg);
    --bs-btn-hover-bg: var(--color-sage);
    --bs-btn-hover-border-color: var(--color-sage);
    --bs-btn-active-color: var(--color-bg);
    --bs-btn-active-bg: var(--color-sage);
    --bs-btn-active-border-color: var(--color-sage);
    --bs-btn-disabled-color: var(--color-sage);
    --bs-btn-disabled-border-color: var(--color-sage);
    --bs-btn-focus-shadow-rgb: var(--color-sage-rgb);
}

/* Bootstrap 5.3.3's .form-control:focus/.form-select:focus/
   .form-check-input:focus/:checked all bake in a literal blue
   (border-color:#86b7fe, box-shadow color rgba(13,110,253,...)) in its
   compiled CSS -- NOT a var() read at runtime, despite --bs-focus-ring-color
   existing as a documented custom property elsewhere in Bootstrap. Setting
   that variable (see :root above) has no effect on these specific rules, so
   every plain text input, native <select>, checkbox, and radio in the app
   showed Bootstrap's stock blue on focus/checked regardless of theme --
   TomSelect-enhanced dropdowns and .toggle-pill's hidden radios were
   already fine since those read through --bs-btn-* / --color-sage directly,
   not this hardcoded rule. Higher-specificity page-local rules (e.g.
   .milestone-toggle:checked in action_plans.html) still win where they
   already exist; this is just the sage-colored default for everything
   that didn't have one. */
.form-control:focus,
.form-select:focus,
.form-check-input:focus {
    border-color: var(--color-sage);
    box-shadow: 0 0 0 .25rem rgba(var(--color-sage-rgb), .25);
}
.form-check-input:checked {
    background-color: var(--color-sage);
    border-color: var(--color-sage);
}
/* Bootstrap's unchecked .form-check-input border reads --bs-border-color
   (-> --color-border), the same subtle hairline token used for card/table
   dividers -- fine for a divider, but a checkbox's border is the ONLY thing
   drawing its shape when unchecked, and --color-border measures ~1.2-1.5:1
   against the surrounding card/page background in every theme (checked
   with the WCAG contrast formula), well under the 3:1 WCAG non-text
   contrast minimum for UI components. --color-text-muted reuses an
   existing token (no new one needed) and clears >=3.9:1 against every
   theme's card/page background, so unchecked boxes (e.g. the Pre-Market
   Routine checklist) are actually visible instead of blending into the
   background until checked. */
.form-check-input {
    border-color: var(--color-text-muted);
}
/* The native file input's "Choose Files" button is styled by Bootstrap via
   ::file-selector-button, with background-color: var(--bs-tertiary-bg) --
   a Bootstrap variable this app never repoints per theme (unlike
   --bs-body-bg/--bs-body-color above), so it stayed Bootstrap's default
   light gray/white no matter the theme, standing out against the dark
   Upload Images field around it. Overridden directly with the app's own
   surface tokens instead of also repointing --bs-tertiary-bg globally,
   since that variable isn't used anywhere else in the app. */
.form-control::file-selector-button {
    color: var(--color-text);
    background-color: var(--color-neutral-subtle);
}
.form-control:hover:not(:disabled):not([readonly])::file-selector-button {
    background-color: var(--color-border);
}

/* Bootstrap tooltips (e.g. the Charts/Add Trade info icons) default to a
   plain black bubble at 90% opacity -- background overridden to a soft
   charcoal (lighter than pure black, so it doesn't look like a harsh cutout)
   with white text kept, so the tooltip reads as a solid, high-contrast UI
   element without introducing its own accent hue (slategray's blue
   undertone and a lighter gray fill both read as an odd extra color against
   the rest of the page). Opacity is bumped to fully solid since Bootstrap's
   --bs-tooltip-opacity applies to the whole element (not just the
   background), which let whatever sits behind it show through. The arrow
   inherits --bs-tooltip-bg automatically, no separate override needed. */
.tooltip {
    --bs-tooltip-bg: #525252;
    --bs-tooltip-color: #fff;
    --bs-tooltip-opacity: 1;
}

/* TomSelect (Account/Status/Strategies/etc. dropdowns on Trade Dashboard's
   filters and Add/Edit Trade) ships its own vendor stylesheet
   (tom-select.bootstrap5.min.css) with hardcoded light colors -- the
   dropdown popup stayed a fixed white/light-gray regardless of theme, while
   its option text inherited var(--color-text) (light-colored in dark
   themes), landing light-on-light and reading as "not visible at all."
   Same underlying problem color-scheme fixes for *native* control popups
   (see :root above), but TomSelect's dropdown is a plain styled <div>, not
   native browser chrome, so it needs its own explicit override instead. */
.ts-wrapper .ts-control {
    color: var(--color-text);
}
.ts-wrapper .ts-control input {
    color: var(--color-text);
}
.ts-dropdown {
    background: var(--color-surface);
    border-color: var(--color-border);
    color: var(--color-text);
}
/* The vendor stylesheet already sets its own (much flatter) box-shadow on
   .ts-dropdown, and -- same recurring issue as the Flatpickr overrides
   above -- base.html renders extra_css's tom-select CDN link AFTER
   base.css's own <link>, so at equal specificity the vendor rule wins the
   source-order tie-break regardless of which file "should" win. "html "
   outranks it by specificity instead of resorting to !important, same
   trick used throughout this file. Without a real elevation shadow, an
   open dropdown that overlaps something below it (e.g. Charts' Platform
   filter over the stat-tile cards, whose background is the exact same
   flat --color-surface) has nothing to visually read as "floating above"
   -- it looks like the page layout itself is resizing. Same shadow value
   as the Flatpickr calendar popup, for the same reason and for visual
   consistency between the app's two floating-popup patterns. */
html .ts-dropdown {
    box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
}
.ts-dropdown .ts-dropdown-content .option {
    color: var(--color-text);
}
/* .create (the "Add <typed text>…" row TomSelect shows for a creatable
   field, e.g. Strategies/Platform) is a sibling of .option, not one --
   the .option.active override above never matched it, so its highlighted
   state fell through to the vendor stylesheet's own hardcoded light-mode
   active background (#f8f9fa), landing near-white text on a near-white
   pill in dark/deep-sage themes. */
.ts-dropdown .ts-dropdown-content .option.active,
.ts-dropdown .ts-dropdown-content .create.active {
    background: var(--color-neutral-subtle);
    color: var(--color-text);
}
.ts-dropdown .no-results {
    color: var(--color-text-muted);
}
/* TomSelect's own vendor CSS also hardcodes the same Bootstrap blue
   (border-color:#86b7fe, box-shadow rgba(13,110,253,...)) on its
   ".focus .ts-control" rule -- a separate stylesheet from Bootstrap's own
   .form-control:focus/etc (already overridden above), since a TomSelect
   dropdown is a wrapper <div> toggling a .focus class, not a real
   <select>/<input> matching the :focus pseudo-class. Every TomSelect
   dropdown in the app (Account, Grade, Asset Class, Strategies, ...)
   showed this blue ring until it was overridden here too. */
.ts-wrapper.focus .ts-control {
    border-color: var(--color-sage);
    box-shadow: 0 0 0 .25rem rgba(var(--color-sage-rgb), .25);
}
/* A TomSelect control's search <input> keeps a real reserved width even
   after an item is selected (room to type a new search), and the control's
   flex row is allowed to wrap by default -- fine when the selected item's
   text is short, but a longer one (e.g. "Single Call/Put" in Add Trade's
   Structure dropdown, "Micro E-mini Russell 2000" in Futures Contract)
   plus that reserved input width together exceed a normal column width,
   wrapping the input onto its own line and visibly growing the control's
   height. Originally fixed only for Charts' Platform filter (scoped to
   .filter-field there) -- generalized here since the same wrap happens on
   any narrow-ish TomSelect field with a long enough option label,
   regardless of page. nowrap forces single-line always; the two rules
   below then reassign the freed-up space so the selected item's text (not
   the now-idle input) gets first claim on it, ellipsis-truncating instead
   of pushing the input down.

   .single-scoped, not a blanket .ts-wrapper -- a multi-select (Strategies,
   Mistake, both using the remove_button plugin) is a completely different
   shape: several .item chips that should each size to their own text and
   wrap onto new lines as more get added, not one item competing with an
   idle input for space on a single forced line. Applying this to .multi
   too made every chip flex-grow to fill the row, splitting the width
   evenly across however many chips existed (so the highlighted background
   stretched well past the actual text, and shrank as more chips were
   added) -- exactly the vendor's own correct default (content-sized
   chips, normal wrapping) that this rule was accidentally overriding. */
.ts-wrapper.single .ts-control { flex-wrap: nowrap; overflow: hidden; }
.ts-wrapper.single .ts-control > .item {
    flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* Sibling-scoped (~), not a blanket "> input" rule -- with nothing selected
   there's no .item at all, so the input is .ts-control's only child and
   needs its normal flex:1 1 auto (the vendor default) to show its full
   placeholder text ("All Platforms", "---------", ...) instead of being
   squeezed down to a couple characters by the shrink-priority rule above,
   which is only meant to give way to an actual selected item. */
.ts-wrapper.single .ts-control > .item ~ input {
    flex: 0 1 auto; min-width: 0;
}
/* TomSelect's vendor CSS hardcodes Bootstrap's stock blue as the background
   of a clicked/keyboard-focused chip in a multi-select (e.g. Strategies,
   Mistake) -- same "separate stylesheet, doesn't read this app's theme
   variables" issue as .ts-wrapper.focus above, just on .item.active
   instead of the wrapper itself. The vendor's own rule is
   ".ts-wrapper.multi .ts-control>div.active" (4 classes + 1 element) --
   matching just ".ts-wrapper .ts-control > .item.active" (also 4 classes +
   1 element via the "html" prefix) ties on specificity, and base.html
   loads the vendor CDN stylesheet after base.css, so the later vendor rule
   would still win that tie. Adding ".multi" here (5 classes + 1 element)
   is what actually outweighs it, not just the "html" prefix alone. */
html .ts-wrapper.multi .ts-control > .item.active {
    background: var(--color-sage);
    color: var(--color-bg);
}

/* Sliding-pill toggle -- a two-option radio group (native <input
   type="radio" class="btn-check"> + <label> pairs, same accessible/
   keyboardable/form-submittable markup Bootstrap's own .btn-check pattern
   already used) with one indicator that glides behind whichever label is
   checked, instead of two separately-colored buttons. Used by the Charts
   page's Account filter and the Trade Dashboard's Merged Ledger LIVE/SIM
   toggle. The thumb's slide is driven by a tiny "change"-listener on each
   page (toggles .is-second on .toggle-pill) rather than a pure-CSS
   :has() selector, so it behaves identically whether the radios actually
   submit a form (Charts) or are just local UI state (Dashboard). */
.toggle-pill {
    position: relative;
    display: inline-flex;
    background: var(--color-neutral-subtle);
    border-radius: 100px;
    padding: 3px;
}
.toggle-pill .toggle-thumb {
    position: absolute;
    top: 3px;
    bottom: 3px;
    left: 3px;
    width: calc(50% - 3px);
    background: var(--color-sage-dark);
    border-radius: 100px;
    /* Charts' toggle also uses this component, but that page navigates
       (form.submit()) ~100ms after the click -- well before a .22s
       transition would finish -- so it only ever reads as a quick partial
       flick before the reload cuts it off and shows the final state
       instantly. The Dashboard toggle doesn't navigate, so the old .22s
       played out in full and felt slower/different by comparison. Shortened
       to actually complete around the same ~100-130ms window Charts gets by
       accident, so both feel equally snappy. */
    transition: transform .13s cubic-bezier(.4, 0, .2, 1), background-color .13s ease;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .15);
}
.toggle-pill.is-second .toggle-thumb {
    transform: translateX(100%);
    /* Plain ink, not a second brand hue -- SIM has no color identity
       anywhere else in the app (its row/status pills are neutral gray), so
       giving it slate here made the toggle the only place SIM read as
       "blue" and the only place LIVE/SIM looked like a 3rd unrelated color
       pair instead of "accent vs. neutral." color-text (not
       color-text-muted) because the label text on top needs >=4.5:1
       contrast against white -- text-muted only clears ~4.25:1. */
    background: var(--color-text);
}
/* --color-text is deliberately near-black in light theme (see the comment
   above) but flips to a near-white/light gray in dark and deep-sage themes
   -- correct for body copy, but reused as a pill FILL here it made the SIM
   thumb turn bright white while LIVE's thumb (--color-sage-dark) stays a
   medium-toned green, an inconsistent "second color" the toggle didn't
   have in light theme. --color-text-muted's dark/deep-sage values happen
   to land at nearly the same lightness as --color-sage-dark's, so swapping
   to it here keeps SIM reading as a plain, similarly-weighted neutral
   pill instead of white -- still >=4.5:1 for the checked label's
   var(--color-bg) text in both themes, just not enough margin for light
   theme's own text-muted (see the comment above), which is why this only
   overrides dark/deep-sage rather than changing the base rule. */
[data-theme="dark"] .toggle-pill.is-second .toggle-thumb,
[data-theme="deep-sage"] .toggle-pill.is-second .toggle-thumb {
    background: var(--color-text-muted);
}
.toggle-pill input.btn-check {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.toggle-pill label {
    position: relative;
    z-index: 1;
    flex: 1;
    text-align: center;
    font-size: 12.5px;
    font-weight: 700;
    padding: 7px 16px;
    border-radius: 100px;
    cursor: pointer;
    color: var(--color-text-muted);
    transition: color .13s ease;
    margin: 0;
    white-space: nowrap;
}
/* var(--color-bg), not white -- the LIVE thumb (sage-dark) and SIM thumb
   (color-text, see .is-second above) both get deliberately brightened in
   dark themes so they read against a near-black page, which means white
   text on top of them stops being legible. color-bg self-corrects: it's
   near-white in light theme (matches the old hardcoded white) and
   near-black in dark themes (correct once the thumb itself goes light). */
.toggle-pill input:checked + label {
    color: var(--color-bg);
}
.toggle-pill input:focus-visible + label {
    outline: 2px solid var(--color-sage);
    outline-offset: 2px;
}

body {
    background-color: var(--color-bg);
    color: var(--color-text);
}
/* The old body{padding:30px 0} applied to everything including the
   sidebar, which needs to run flush to the viewport edges -- moved onto
   the content container itself (applied to every page, authenticated or
   not, via base.html's page-padding class on that container). */
.page-padding {
    padding-top: 24px;
    padding-bottom: 24px;
}

.card {
    background-color: var(--color-surface);
    border-radius: 12px;
    border: none;
    box-shadow: 0 4px 20px rgba(90, 80, 60, 0.07);
}

.section-title {
    font-size: 0.9rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--color-text-muted);
    border-bottom: 2px solid var(--color-border);
    padding-bottom: 5px;
    margin-bottom: 20px;
    margin-top: 20px;
}

.detail-label {
    font-weight: bold;
    color: var(--color-text-muted);
    font-size: 0.8rem;
}

.detail-value {
    font-size: 1.1rem;
    margin-bottom: 15px;
}

.img-container img {
    max-width: 100%;
    border-radius: 10px;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}

.ticker-badge {
    font-size: 1rem;
    font-weight: bold;
    color: var(--color-sage-dark);
}

/* Read-only display of user-typed free text (journal, technical analysis):
   preserves the exact line breaks/spacing the textarea already preserved on
   entry, instead of HTML's default collapsing everything onto one line. */
.text-preserve-format {
    white-space: pre-wrap;
    word-wrap: break-word;
}

/* Applied via BOOTSTRAP5["required_css_class"] (see settings.py) to every
   field's wrapper div where the underlying model field is actually required
   (blank=False) -- marks it with a red asterisk without needing to touch
   each {% bootstrap_field %} call individually. Scoped to .form-label (the
   field's own label) rather than any nested label -- a RadioSelect/
   CheckboxSelectMultiple renders one .form-check-label per choice inside
   the same wrapper, which would otherwise get a stray asterisk too. */
.required-field label.form-label::after {
    content: " *";
    color: var(--color-clay-dark);
}

/* Quieter alternative to Bootstrap's default table-bordered grid -- used for
   read-only detail tables (e.g. trade legs) so they match the rest of a
   detail page's clean, label/value look instead of standing out as a bolted-on
   spreadsheet grid. */
.table-elegant {
    border-collapse: collapse;
}
.table-elegant thead th {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--color-text-muted);
    border: none;
    border-bottom: 2px solid var(--color-border);
    padding: 8px 12px;
}
.table-elegant tbody td {
    border: none;
    border-bottom: 1px solid var(--color-border);
    padding: 10px 12px;
    vertical-align: middle;
    /* Bootstrap's .table bakes in its own near-black text color rather than
       reading a var() at runtime (same issue as .form-control:focus above),
       so without this every table-elegant cell stayed dark-on-dark in Dark
       theme -- .trades-grid already patches this locally for its own table,
       this is the same fix at the shared level so the trade-legs table
       (view_trade.html) gets it too instead of being missed. */
    color: var(--color-text);
}
.table-elegant tbody tr:last-child td {
    border-bottom: none;
}
.table-elegant tbody tr:hover {
    background-color: var(--color-sage-subtle);
}

/* ============================================================
   App shell: left sidebar nav (replaces the old top nav bar) + a
   Feedback & Support footer that appears under every authenticated
   page's content automatically, since it lives in base.html rather
   than each individual template.
   ============================================================ */
.app-shell { display: flex; min-height: 100vh; }

/* Sticky + its own 100vh, not just a flex child stretched to match
   .app-shell's height -- without this, a page taller than one viewport
   (most of them) stretches the whole flex row taller, and the sidebar
   (whose logout button is pinned to ITS bottom via margin-top:auto)
   stretches right along with it, pushing logout down past the actual
   viewport. Sticky keeps the sidebar's own scroll position locked to the
   viewport regardless of how long the main content next to it runs. */
.app-sidebar {
    flex: 0 0 246px; background: var(--color-surface); border-right: 1px solid var(--color-border);
    display: flex; flex-direction: column; padding: 22px 16px;
    position: sticky; top: 0; height: 100vh; overflow-y: auto;
    z-index: 10;
}
.sidebar-brand {
    display: flex; align-items: center; gap: 9px; padding: 0 8px 20px; margin-bottom: 14px;
    border-bottom: 1px solid var(--color-border);
}
.sidebar-brand-mark {
    width: 30px; height: 30px; border-radius: 50%;
    background: linear-gradient(135deg, var(--color-sage) 0%, var(--color-sage-dark) 100%);
    display: grid; place-content: center; flex: 0 0 auto;
}
.sidebar-brand-mark svg { width: 17px; height: 17px; stroke: #fff; }
.sidebar-brand-name { font-weight: 700; font-size: 0.95rem; letter-spacing: -0.01em; color: var(--color-text); }

.sidebar-nav { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.sidebar-nav-item {
    display: flex; align-items: center; gap: 11px; padding: 9px 10px; border-radius: 9px;
    color: var(--color-text); text-decoration: none; font-size: 0.875rem; font-weight: 600;
    transition: background 120ms ease, color 120ms ease;
}
.sidebar-nav-item svg { width: 18px; height: 18px; flex: 0 0 auto; stroke: var(--color-text-muted); transition: stroke 120ms ease; }
.sidebar-nav-item:hover { background: var(--color-neutral-subtle); color: var(--color-text); }
.sidebar-nav-item.active { background: var(--color-sage-subtle); color: var(--color-sage-emphasis); }
.sidebar-nav-item.active svg { stroke: var(--color-sage-dark); }

/* Logout now occupies the row the user avatar/name used to (removed --
   the username was already visible in every browser tab/session anyway),
   as a full-width button matching .sidebar-nav-item's own row shape
   instead of a small icon-only square, so it reads as a proper action in
   the list rather than a corner affordance. A visible label replaces the
   old hover-only tooltip, since there's now room for one. */
.sidebar-footer {
    margin-top: auto; padding-top: 16px; border-top: 1px solid var(--color-border);
}
.sidebar-logout {
    display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 8px 10px; border-radius: 8px; border: none; background: none;
    font: inherit; font-size: 0.85rem; font-weight: 600; text-align: left;
    color: var(--color-text-muted);
    transition: background 120ms ease, color 120ms ease;
}
.sidebar-logout svg { width: 18px; height: 18px; flex: 0 0 auto; }
.sidebar-logout .nav-label { white-space: nowrap; }
.sidebar-logout:hover { color: var(--color-clay-dark); background: var(--color-clay-subtle); }

.app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.app-main > .container, .app-main > .container-fluid { flex: 1; width: 100%; }

/* Sitewide processing indicator -- see journal/js/loading-indicator.js.
   Fixed/full-width regardless of the sidebar, so it reads as "the whole
   app is busy" rather than being scoped to just .app-main. */
#app-loading-bar {
    position: fixed; top: 0; left: 0; height: 3px; width: 0%;
    background: var(--color-sage); z-index: 2000;
    transition: width 200ms ease-out, opacity 200ms ease;
    opacity: 0;
    pointer-events: none;
}

.app-footer {
    margin: 12px auto 12px; padding-top: 12px; border-top: 1px solid var(--color-border);
    display: flex; align-items: center; justify-content: center; gap: 6px;
    font-size: 0.8rem; color: var(--color-text-muted); max-width: 1140px; width: 100%; padding-left: 12px; padding-right: 12px;
}
.app-footer a { color: var(--color-sage-dark); font-weight: 600; text-decoration: none; }
.app-footer a:hover { text-decoration: underline; }

@media (max-width: 860px) {
    .app-shell { flex-direction: column; }
    .app-sidebar {
        /* height:100vh (set for the desktop column layout, so the sidebar
           can be sticky+its-own-scroll) would make this horizontal strip
           take up the entire screen height on mobile -- reset to content
           height; overflow-y is dropped too since there's nothing to
           scroll here past the strip's own row. */
        flex: 0 0 auto; flex-direction: row; align-items: center; gap: 14px;
        padding: 12px 16px; height: auto; overflow-x: auto; overflow-y: visible;
    }
    .sidebar-brand { border-bottom: none; padding: 0; margin: 0; flex: 0 0 auto; }
    .sidebar-nav { flex-direction: row; flex: 0 0 auto; }
    .sidebar-nav-item span.nav-label { white-space: nowrap; }
    .sidebar-footer { margin-top: 0; padding-top: 0; border-top: none; margin-left: auto; flex: 0 0 auto; }
    .sidebar-logout { width: auto; }
}

/* ============================================================
   FLATPICKR -- replaces every native <input type="date"/"time"> in the app
   (Charts date range, Trade Dashboard filters, Add/Edit Trade's Entry/Exit
   Date & Time). The native picker's calendar/time popup is OS-native chrome
   that no amount of CSS can restyle -- it always renders Chrome/Safari/
   Firefox's own blue, in every theme, regardless of anything set on the
   <input> itself (border-color, color-scheme, etc. only affect the input
   box, never the popup). Flatpickr draws its own popup as plain HTML/CSS,
   so it can actually be reskinned -- this block replaces its stock blue
   (#569ff7, hardcoded in flatpickr's own CSS, not a variable) with this
   app's sage/theme tokens throughout. Each <input> gets wrapped via
   altInput: true (see the JS in each page), which leaves the ORIGINAL input
   (name/value Django's form posts against) as a hidden field and creates a
   separate visible text input for the user to interact with -- that visible
   input carries class "form-control flatpickr-alt-input" so it already
   picks up this app's existing .form-control focus-ring override (see
   .form-control:focus above) without needing its own rule here.

   Every selector below is prefixed with a redundant "html " -- flatpickr's
   own CDN stylesheet loads via each page's {% block extra_css %}, which
   base.html renders AFTER base.css, so at equal specificity flatpickr's
   own rules would win the source-order tie-break and this block would be
   silently dead. "html " adds one type-selector's worth of specificity
   (matches every element in the page, so it changes nothing about what
   actually gets selected) without resorting to !important. */
html .flatpickr-calendar {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
    /* Flatpickr's default day-grid math assumes 39px cells (7 * 39px +
       padding = its stock 307.875px), sized for a full-width form field --
       comically large next to the compact filter/form inputs it's actually
       attached to on every page here. .flatpickr-days/.dayContainer pin
       their own width to that same 307.875px in flatpickr's own CSS, so
       both need the matching override below or the day grid clips/
       misaligns against a narrower .flatpickr-calendar. */
    width: 216px;
}
html .flatpickr-days,
html .dayContainer {
    width: 216px;
    min-width: 216px;
    max-width: 216px;
}
html .flatpickr-day {
    max-width: 30px;
    height: 30px;
    line-height: 30px;
}
html .flatpickr-calendar.arrowTop:before,
html .flatpickr-calendar.arrowTop:after {
    border-bottom-color: var(--color-border);
}
html .flatpickr-calendar.arrowTop:after {
    border-bottom-color: var(--color-surface);
}
html .flatpickr-calendar.arrowBottom:before,
html .flatpickr-calendar.arrowBottom:after {
    border-top-color: var(--color-border);
}
html .flatpickr-calendar.arrowBottom:after {
    border-top-color: var(--color-surface);
}
html .flatpickr-months .flatpickr-month,
html .flatpickr-current-month,
html .flatpickr-current-month .cur-month,
html .flatpickr-current-month input.cur-year {
    color: var(--color-text);
    fill: var(--color-text);
    background: transparent;
}
/* flatpickr's own default (135% of the calendar's 14px base, ~19px) reads
   oversized next to the compact 30px day cells above -- toned down to
   match. */
html .flatpickr-current-month {
    font-size: 100%;
}
html .flatpickr-months .flatpickr-prev-month,
html .flatpickr-months .flatpickr-next-month {
    color: var(--color-text);
    fill: var(--color-text);
}
/* flatpickr's own weekday rule is "span.flatpickr-weekday", not just
   ".flatpickr-weekday" -- same specificity as a plain "html .flatpickr-
   weekday" override (one type selector either way), so it was winning the
   source-order tie-break the same way the calendar/day rules above would
   have without "html ". Matched here with the same "span" so this one
   actually wins too, instead of staying flatpickr's stock
   rgba(0,0,0,.54) -- a hardcoded near-black that reads as invisible-ish
   against a dark card, not just "not themed." */
html span.flatpickr-weekday {
    color: var(--color-text-muted);
    background: transparent;
}
html .flatpickr-day {
    color: var(--color-text);
}
html .flatpickr-day.prevMonthDay,
html .flatpickr-day.nextMonthDay,
html .flatpickr-day.flatpickr-disabled,
html .flatpickr-day.flatpickr-disabled:hover {
    color: var(--color-text-muted);
    opacity: .5;
}
html .flatpickr-day:hover,
html .flatpickr-day:focus,
html .flatpickr-day.prevMonthDay:hover,
html .flatpickr-day.nextMonthDay:hover {
    background: var(--color-neutral-subtle);
    border-color: var(--color-neutral-subtle);
}
html .flatpickr-day.today {
    border-color: var(--color-picker-accent);
}
html .flatpickr-day.today:hover,
html .flatpickr-day.today:focus {
    background: var(--color-picker-accent);
    border-color: var(--color-picker-accent);
    color: var(--color-bg);
}
html .flatpickr-day.selected,
html .flatpickr-day.startRange,
html .flatpickr-day.endRange,
html .flatpickr-day.selected.inRange,
html .flatpickr-day.startRange.inRange,
html .flatpickr-day.endRange.inRange,
html .flatpickr-day.selected:focus,
html .flatpickr-day.startRange:focus,
html .flatpickr-day.endRange:focus,
html .flatpickr-day.selected:hover,
html .flatpickr-day.startRange:hover,
html .flatpickr-day.endRange:hover,
html .flatpickr-day.selected.prevMonthDay,
html .flatpickr-day.startRange.prevMonthDay,
html .flatpickr-day.endRange.prevMonthDay,
html .flatpickr-day.selected.nextMonthDay,
html .flatpickr-day.startRange.nextMonthDay,
html .flatpickr-day.endRange.nextMonthDay {
    background: var(--color-picker-accent);
    border-color: var(--color-picker-accent);
    color: var(--color-bg);
}
html .flatpickr-day.inRange,
html .flatpickr-day.prevMonthDay.inRange,
html .flatpickr-day.nextMonthDay.inRange {
    background: var(--color-sage-subtle);
    border-color: var(--color-sage-subtle);
    box-shadow: -5px 0 0 var(--color-sage-subtle), 5px 0 0 var(--color-sage-subtle);
}
html .flatpickr-time input,
html .flatpickr-time .flatpickr-time-separator,
html .flatpickr-time .flatpickr-am-pm {
    color: var(--color-text);
}
html .flatpickr-time input:hover,
html .flatpickr-time input:focus,
html .flatpickr-time .flatpickr-am-pm:hover,
html .flatpickr-time .flatpickr-am-pm:focus {
    background: var(--color-neutral-subtle);
}
/* flatpickr's own CSS scopes a SECOND, more specific rule for each context
   a numInputWrapper spinner appears in -- the year spinner
   (".flatpickr-current-month .numInputWrapper span.arrowUp:after",
   near-black at 90% opacity) and the Entry/Exit Time hour/minute spinners
   (".flatpickr-time .numInputWrapper span.arrowUp:after", hardcoded
   #393939) both beat a plain "html .numInputWrapper span.arrowUp:after" on
   specificity alone -- matched here with both scopes so this rule actually
   wins in every context instead of just the year spinner (the time-picker
   arrows were still invisible in dark theme until this was added).
   Arrows are also opacity:0 by default in flatpickr's CSS (shown only on
   ".numInputWrapper:hover"), which combined with the near-black color made
   them read as simply not there in dark theme -- set to always-visible
   here too so every spinner reads as an obviously adjustable control
   instead of plain text. */
html .numInputWrapper span {
    opacity: 1;
}
html .numInputWrapper span.arrowUp:after,
html .flatpickr-current-month .numInputWrapper span.arrowUp:after,
html .flatpickr-time .numInputWrapper span.arrowUp:after {
    border-bottom-color: var(--color-text-muted);
}
html .numInputWrapper span.arrowDown:after,
html .flatpickr-current-month .numInputWrapper span.arrowDown:after,
html .flatpickr-time .numInputWrapper span.arrowDown:after {
    border-top-color: var(--color-text-muted);
}
/* Flatpickr toggles this on the ORIGINAL (now-hidden) input when the popup
   is open -- harmless to leave targetable in case any page's own CSS ever
   keys off :focus on that hidden input. No visible effect since altInput
   is what's actually on screen. */
html .flatpickr-input[readonly] {
    cursor: pointer;
}
/* Clear/Today footer -- flatpickr has no built-in equivalent, so each
   date-only picker's onReady hook (see the JS in each page) appends this
   itself, styled to match. Plain text links, not buttons -- a bordered
   button pair read as too visually heavy for what's just a shortcut,
   sitting right below a whole grid of already-clickable day buttons. */
html .flatpickr-footer {
    display: flex;
    justify-content: center;
    gap: 16px;
    padding: 6px;
    border-top: 1px solid var(--color-border);
}
html .flatpickr-footer-link {
    background: none;
    border: none;
    padding: 2px 4px;
    font-size: 12px;
    font-weight: 600;
    color: var(--color-sage-dark);
    text-decoration: underline;
    cursor: pointer;
}
html .flatpickr-footer-link:hover,
html .flatpickr-footer-link:focus-visible {
    color: var(--color-picker-accent);
    outline: none;
}
