:root {
  --theme-palette-primary: #1DE4EB;
  --theme-palette-secondary: #ff4c48;
  --theme-palette-light: #FFFFFF;
  --theme-palette-soft-light: #F8F8F7;
  --theme-palette-dark: #101828;
  --theme-palette-soft-dark: #121A23;
  --theme-palette-light-borders: #D7D7D7;
  --theme-palette-dark-borders: #6E7879;
  --theme-palette-error: #ff4c48;
  --theme-palette-warning: #ffe112;
  --theme-palette-success: #0ab67b;

  /* BDS --Color* aliases. On legacy pages these are otherwise only defined inside a
     BDS <ThemeProvider>, so BDS components rendered OUTSIDE one (e.g. profile
     Notification Settings' Text) fall back to their hardcoded light default
     (var(--ColorDark, #3c4153)) — invisible on dark. Define them globally as the
     flipping palette tokens so every BDS component resolves the right value in both
     modes (they follow --theme-palette-* which the [data-theme="dark"] block flips). */
  --ColorPrimary: var(--theme-palette-primary);
  --ColorSecondary: var(--theme-palette-secondary);
  --ColorLight: var(--theme-palette-light);
  --ColorSoftLight: var(--theme-palette-soft-light);
  --ColorLightBorders: var(--theme-palette-light-borders);
  --ColorDark: var(--theme-palette-dark);
  --ColorSoftDark: var(--theme-palette-soft-dark);
  --ColorDarkBorders: var(--theme-palette-dark-borders);
  --ColorError: var(--theme-palette-error);
  --ColorWarning: var(--theme-palette-warning);
  --ColorSuccess: var(--theme-palette-success);
}

/* Dark-mode spike: mirror of :root with the per-instance dark palette
   (THEME_DARK_PALETTE_*, settings/style/theme.py). Cascades over :root whenever
   <html data-theme="dark"> is set by the theme controller in base.html. Every
   legacy surface that reads --theme-palette-* / --Color* flips for free; surfaces
   still using compile-time LESS hex (@brand-primary etc.) won't and need a
   per-surface override or a LESS->var migration (the spike inventory). */
[data-theme="dark"] {
  /* Render native UI (scrollbars, date/number inputs, form controls) in dark so
     they stop flashing a bright thumb/well against the dark surfaces. */
  color-scheme: dark;
  --theme-palette-primary: #1686FF;
  --theme-palette-secondary: #8252FF;
  --theme-palette-light: #292C39;
  --theme-palette-soft-light: #4D546A;
  --theme-palette-dark: #FFFFFF;
  --theme-palette-soft-dark: #F6F9FB;
  --theme-palette-light-borders: #7C8A9C;
  --theme-palette-dark-borders: #E4ECF3;
  --theme-palette-error: #E3000F;
  --theme-palette-warning: #F3BE02;
  --theme-palette-success: #008A00;
}

/* BDS text-color tokens (--text-color-*). BDS <Text> reads these
   (.Text__dark{color:var(--text-color-dark)} etc.), and BDS's global theme defines
   them at :root with the LIGHT palette (--text-color-dark:#3c4153) — nothing flips
   them, so body text renders #3c4153 on dark (profile Notification Settings labels,
   dropdown values, and any BDS <Text> outside a provider). Flip the dark-text family
   to the light-in-dark palette tokens. html[data-theme="dark"] (0,1,1) out-specifies
   BDS's own :root (0,1,0) regardless of runtime inject order. The light/softLight
   families are intentionally left (they're text meant for dark/coloured fills). */
html[data-theme="dark"] {
  --text-color-dark: var(--theme-palette-dark);
  --text-color-hardDark: var(--theme-palette-dark);
  --text-color-softDark: var(--theme-palette-soft-dark);
}

/* BDS ThemeProvider namespaces (DIS-3555). Some legacy React islands wrap their
   subtree in a BDS <ThemeProvider> (e.g. profile → NotificationSettings), which
   injects a `.theme-provider-namespace-*` scope that RE-EMITS the whole palette
   at the instance's LIGHT values — shadowing the dark [data-theme="dark"] :root
   block for everything inside it, so BDS Text renders #3C4153 (invisible on dark).
   Re-assert the dark palette on that namespace so the subtree flips. Higher
   specificity than the provider's own `.theme-provider-namespace-X {…}` rule, and
   a no-op for providers already initialised dark. */
html[data-theme="dark"] [class*="theme-provider-namespace"] {
  --theme-palette-primary: #1686FF;
  --theme-palette-secondary: #8252FF;
  --theme-palette-light: #292C39;
  --theme-palette-soft-light: #4D546A;
  --theme-palette-dark: #FFFFFF;
  --theme-palette-soft-dark: #F6F9FB;
  --theme-palette-light-borders: #7C8A9C;
  --theme-palette-dark-borders: #E4ECF3;
  --theme-palette-error: #E3000F;
  --theme-palette-warning: #F3BE02;
  --theme-palette-success: #008A00;
  --ColorPrimary: #1686FF;
  --ColorSecondary: #8252FF;
  --ColorLight: #292C39;
  --ColorSoftLight: #4D546A;
  --ColorLightBorders: #7C8A9C;
  --ColorDark: #FFFFFF;
  --ColorSoftDark: #F6F9FB;
  --ColorDarkBorders: #E4ECF3;
  --ColorError: #E3000F;
  --ColorWarning: #F3BE02;
  --ColorSuccess: #008A00;
  --text-color-dark: #FFFFFF;
  --text-color-hardDark: #FFFFFF;
  --text-color-softDark: #F6F9FB;
}

/* Force light: legacy chapter/event pagebuilder bodies (DIS-3619, the legacy twin of
   DIS-3560's next/ fix). Pageserver-rendered slate content — wrapped in
   `.page-builder-content` by pageserver/lib/PageBuilderStyles — bakes customer-branded
   LIGHT colors and looks broken (dark-on-dark / white-on-white) under dark mode. Every
   [data-theme="dark"] override in this file is var-driven (`color:var(--theme-palette-*)`),
   so re-declaring the LIGHT palette on this subtree makes them all resolve light here —
   custom properties inherit from the nearest ancestor, so `.page-builder-content` wins for
   its subtree while <html data-theme="dark"> stands (no !important; !important governs the
   property cascade, not var resolution). Chrome outside `.page-builder-content` stays dark.
   The 2nd selector (0,3,0) re-wins over the DIS-3555 rule (line ~78, 0,2,1) that would
   otherwise re-darken the BDS `<ThemeProvider namespace="nextjs-root">` wrapper the
   pageserver nests inside the content. Inert when data-theme="dark" is absent
   (light mode / dark_mode flag off), so no light-mode cost. */
/* `.rsvp-ticket-modal` is the event RSVP/ticket modal. It is authored INSIDE the
   force-light event body, but the BDS <Modal> portals it to <body>, and custom
   properties inherit through the DOM (not the React tree) — so it escapes
   `.page-builder-content` and resolves against the DARK palette on <html>. Its own
   surfaces are compile-time light literals (`#f4f8fa`, `var(--palette-white, #fff)`)
   that never flip, so only the TEXT flipped: white-on-white. Re-declaring the light
   palette on the portaled subtree restores the light modal its light page expects
   (DIS-3624). */
[data-theme="dark"] .page-builder-content,
[data-theme="dark"] .page-builder-content [class*="theme-provider-namespace"],
[data-theme="dark"] .rsvp-ticket-modal,
[data-theme="dark"] .rsvp-ticket-modal [class*="theme-provider-namespace"] {
  /* Native controls (scrollbars, date/number pickers) render light in the light subtree. */
  color-scheme: light;
  --theme-palette-primary: #1DE4EB;
  --theme-palette-secondary: #ff4c48;
  --theme-palette-light: #FFFFFF;
  --theme-palette-soft-light: #F8F8F7;
  --theme-palette-dark: #101828;
  --theme-palette-soft-dark: #121A23;
  --theme-palette-light-borders: #D7D7D7;
  --theme-palette-dark-borders: #6E7879;
  --theme-palette-error: #ff4c48;
  --theme-palette-warning: #ffe112;
  --theme-palette-success: #0ab67b;
  /* BDS --Color*/--text-color-* families: at :root these follow --theme-palette-* (so the
     first selector inherits them light for free), but the DIS-3555 namespace block above
     re-points them with LITERAL dark values on `theme-provider-namespace` — re-point them
     back to the (light) palette so BDS text/components in the nested wrapper also flip. */
  --ColorPrimary: var(--theme-palette-primary);
  --ColorSecondary: var(--theme-palette-secondary);
  --ColorLight: var(--theme-palette-light);
  --ColorSoftLight: var(--theme-palette-soft-light);
  --ColorLightBorders: var(--theme-palette-light-borders);
  --ColorDark: var(--theme-palette-dark);
  --ColorSoftDark: var(--theme-palette-soft-dark);
  --ColorDarkBorders: var(--theme-palette-dark-borders);
  --ColorError: var(--theme-palette-error);
  --ColorWarning: var(--theme-palette-warning);
  --ColorSuccess: var(--theme-palette-success);
  --text-color-dark: var(--theme-palette-dark);
  --text-color-hardDark: var(--theme-palette-dark);
  --text-color-softDark: var(--theme-palette-soft-dark);
}

/* Paint the light page canvas. Re-declaring vars isn't enough on its own: the legacy
   <body> stays dark (chrome) and slate text bakes dark-gray literals, so without a light
   surface behind it that text renders dark-on-dark. `var(--theme-palette-*)` here resolves
   against this container's own (light) values re-declared above. */
[data-theme="dark"] .page-builder-content {
  background-color: var(--theme-palette-light);
  color: var(--theme-palette-dark);
}

/* Same reasoning for the portaled RSVP modal: text that INHERITS a color (rather than
   reading a token) would still inherit the dark <body>'s light text. Only `color` is
   set — the BDS <Modal> panel already paints the surface, and the modal's inner
   containers are deliberately transparent, so painting a background here would cover
   them. Resolves against this subtree's own (light) palette re-declared above. */
[data-theme="dark"] .rsvp-ticket-modal {
  color: var(--theme-palette-dark);
}

/* ============================================================================
   Global BDS dark-mode token bridge (DIS-3555) — legacy mirror of
   next/src/app/dark-overrides.css. BDS injects ~130 light-baked CSS vars via a
   `:root { … }` createGlobalStyle; none read the palette, so BDS inputs/selects/
   date-pickers/tabs/pagination on legacy Django pages (search, profile, etc.)
   stay light in dark mode. Re-point the neutral chrome vars to the (dark) palette
   tokens once. On `html[data-theme="dark"]` (specificity 0,1,1) so it beats BDS's
   `:root` (0,1,0) regardless of load order. Brand/signal/selected/disabled states
   and non-color vars (radii/spacing/fonts/shadows) are intentionally left alone. */
html[data-theme="dark"] {
  /* Surfaces (panels, option lists, containers, outlined fields) */
  --select-options-backgroundColor: var(--theme-palette-light);
  --select-label-backgroundColor: var(--theme-palette-light);
  --datePicker-dropdownContainerBackgroundColor: var(--theme-palette-light);
  --datePicker-monthYearDropdown-backgroundColor: var(--theme-palette-light);
  --datePicker-navButtonBackgroundColor: var(--theme-palette-light);
  --datePicker-calendar-monthBackgroundColor: var(--theme-palette-light);
  --datePicker-calendar-yearBackgroundColor: var(--theme-palette-light);
  --pagination-jumpToPage-panelBackgroundColor: var(--theme-palette-light);
  --textfield-label-backgroundColor: var(--theme-palette-light);
  --textarea-label-backgroundColor: var(--theme-palette-light);
  --textfield-variant-outlined-backgroundColor: var(--theme-palette-light);
  --textfield-variant-outlined-active-backgroundColor: var(--theme-palette-light);
  --textarea-variant-outlined-backgroundColor: var(--theme-palette-light);
  --textarea-variant-outlined-active-backgroundColor: var(--theme-palette-light);

  /* Subtle / filled surfaces + hover/focus tints */
  --textfield-variant-filled-backgroundColor: var(--theme-palette-soft-light);
  --textfield-variant-filled-active-backgroundColor: var(--theme-palette-soft-light);
  --textfield-variant-outlinedFilled-backgroundColor: var(--theme-palette-soft-light);
  --textfield-variant-outlinedFilled-active-backgroundColor: var(--theme-palette-soft-light);
  --textarea-variant-filled-backgroundColor: var(--theme-palette-soft-light);
  --textarea-variant-filled-active-backgroundColor: var(--theme-palette-soft-light);
  --textarea-variant-outlinedFilled-backgroundColor: var(--theme-palette-soft-light);
  --textarea-variant-outlinedFilled-active-backgroundColor: var(--theme-palette-soft-light);
  --pagination-pageButtonHoverBackgroundColor: var(--theme-palette-soft-light);
  --pagination-pageButtonActiveBackgroundColor: var(--theme-palette-soft-light);
  --pagination-enabledArrowButtonBackgroundColor: var(--theme-palette-soft-light);
  --pagination-enabledArrowButtonFocusBackgroundColor: var(--theme-palette-soft-light);
  --tab-hover-background: var(--theme-palette-soft-light);
  --select-option-hoverColor: var(--theme-palette-soft-light);
  --select-option-focusColor: var(--theme-palette-soft-light);

  /* Foreground / value text */
  --textfield-variant-outlined-color: var(--theme-palette-dark);
  --textfield-variant-filled-color: var(--theme-palette-dark);
  --textfield-variant-outlinedFilled-color: var(--theme-palette-dark);
  --textarea-variant-outlined-color: var(--theme-palette-dark);
  --textarea-variant-filled-color: var(--theme-palette-dark);
  --textarea-variant-outlinedFilled-color: var(--theme-palette-dark);
  --datePicker-calendar-monthColor: var(--theme-palette-dark);
  --datePicker-calendar-yearColor: var(--theme-palette-dark);
  --datePicker-monthYearDropdown-color: var(--theme-palette-dark);
  --datePicker-navButtonColor: var(--theme-palette-dark);
  --pagination-pageButtonColor: var(--theme-palette-dark);
  --pagination-enabledArrowButtonColor: var(--theme-palette-dark);
  --pagination-enabledArrowButtonFocusColor: var(--theme-palette-dark);

  /* Subtle text (labels, hints, dividers, inactive tab) */
  --textfield-label-color: var(--theme-palette-soft-dark);
  --textarea-label-color: var(--theme-palette-soft-dark);
  --select-label-color: var(--theme-palette-soft-dark);
  --tab-font-color: var(--theme-palette-soft-dark);
  --pagination-jumpToPage-labelColor: var(--theme-palette-soft-dark);
  --pagination-jumpToPage-hintColor: var(--theme-palette-soft-dark);
  --pagination-jumpToPage-triggerColor: var(--theme-palette-soft-dark);
  --pagination-jumpToPage-triggerHoverColor: var(--theme-palette-dark);
  --pagination-jumpToPage-dividerColor: var(--theme-palette-light-borders);

  /* Resting border colors */
  --select-border-color: var(--theme-palette-light-borders);
  --select-label-borderColor: var(--theme-palette-light-borders);
  --tab-variant-switch-borderColor: var(--theme-palette-light-borders);
  --pagination-jumpToPage-panelBorderColor: var(--theme-palette-light-borders);
  --textfield-label-borderColor: var(--theme-palette-light-borders);
  --textarea-label-borderColor: var(--theme-palette-light-borders);
  --textfield-variant-outlined-borderColor: var(--theme-palette-light-borders);
  --textfield-variant-outlinedFilled-borderColor: var(--theme-palette-light-borders);
  --textarea-variant-outlined-borderColor: var(--theme-palette-light-borders);
  --textarea-variant-outlinedFilled-borderColor: var(--theme-palette-light-borders);

  /* Active / focus border colors */
  --textfield-variant-outlined-active-borderColor: var(--theme-palette-dark-borders);
  --textfield-variant-filled-active-borderColor: var(--theme-palette-dark-borders);
  --textfield-variant-outlinedFilled-active-borderColor: var(--theme-palette-dark-borders);
  --textarea-variant-outlined-active-borderColor: var(--theme-palette-dark-borders);
  --textarea-variant-filled-active-borderColor: var(--theme-palette-dark-borders);
  --textarea-variant-outlinedFilled-active-borderColor: var(--theme-palette-dark-borders);

  /* Border shorthands ("1px solid <hex>") — containers & interactive states */
  --datePicker-dropdownContainerBorder: 1px solid var(--theme-palette-light-borders);
  --datePicker-monthYearDropdown-border: 1px solid var(--theme-palette-light-borders);
  --datePicker-navButtonFocusBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-calendar-dayHoverBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-calendar-dayActiveBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-calendar-dayFocusBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-calendar-monthHoverBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-calendar-monthActiveBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-calendar-monthFocusBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-calendar-yearHoverBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-calendar-yearActiveBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-calendar-yearFocusBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-monthYearDropdown-hoverBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-monthYearDropdown-activeBorder: 1px solid var(--theme-palette-dark-borders);
  --datePicker-monthYearDropdown-focusBorder: 1px solid var(--theme-palette-dark-borders);
}

/* Dark-mode spike overrides: legacy chrome (navbar, search card) is compiled-LESS
   with authored/hardcoded colors that don't read the tokens, so the flip above can't
   reach it. Re-point the obvious surfaces at the (now dark) neutral tokens at runtime
   — no bundle rebuild. This is the "authored colors need per-surface handling"
   finding, same as next/. Not exhaustive; the real work is a LESS->var migration. */
[data-theme="dark"] header.navs,
[data-theme="dark"] header.navs .navbar,
[data-theme="dark"] header.navs .navbar-secondary {
  background-color: var(--theme-palette-light) !important;
  border-color: var(--theme-palette-light-borders) !important;
}

[data-theme="dark"] header.navs a,
[data-theme="dark"] header.navs button,
[data-theme="dark"] header.navs [class*="Text"],
[data-theme="dark"] header.navs [class*="label"] {
  color: var(--theme-palette-dark) !important;
}

/* DM-031: dark header/footer logo (DIS-3623). A light logo authored for a light header is
   usually illegible once the chrome above flips to dark, so instances can upload a dark
   variant (GENERAL_WEBSITE_{HEADER,FOOTER}_LOGO_DARK_{SVG,PNG}). header.html / footer.html
   ship BOTH layers and these rules pick one, so the swap lands pre-paint with no flash —
   the base.html controller sets data-theme before first paint, whereas a JS src-swap could
   only run after mount. Mirrors next/src/features/global/ThemeAwareLogo.

   Two deliberate properties:
   1. Neither rule sets a POSITIVE display — each only hides the layer the current theme
      doesn't want. .navbar-brand is itself display:flex (navbar.less) and these images pick
      up sizing/positioning from per-theme rules that target `a.navbar-brand > img` /
      `h2.footer-brand > img` (cmx, sheworx, bevylabs, riseoftherest). Hiding-only means we
      never have to pick a single positive `display` value that stays correct for the flex
      parent and every current/future theme. Hence html:not([data-theme="dark"]) for the
      default state rather than a plain `.logo-dark { display: none }` + a positive value
      under dark.
   2. .has-dark-logo gates rule 2: the template only emits that class when a dark variant
      was actually rendered, so an instance without one keeps its light logo in dark mode
      instead of being left logo-less.

   Inert when the dark_mode flag is off: this file is linked unconditionally, but data-theme
   is only ever set by the flag-gated controller, so :not([data-theme="dark"]) matches and
   the dark layer stays hidden. */
html:not([data-theme="dark"]) .navbar-brand .logo-dark,
html:not([data-theme="dark"]) .footer-brand .logo-dark {
  display: none;
}

html[data-theme="dark"] .navbar-brand.has-dark-logo .logo-light,
html[data-theme="dark"] .footer-brand.has-dark-logo .logo-light {
  display: none;
}

/* Search page bar. The SearchBar reads legacy --Color* vars that don't flip, so
   it kept a light background in dark. Search mode and AI mode render the bar over
   *different* page surfaces, so no single token matches both — any fixed color
   shows as a mismatched rectangle in one of the modes. Make the bar chrome
   transparent so it blends with whatever page surface is behind it in either mode;
   the inset SearchInput and the mode-switch toggle keep their own backgrounds. */
[data-theme="dark"] [class*="SearchBar-SearchBar-module-container"] {
  background-color: var(--theme-palette-soft-light) !important;
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] [class*="SearchBar-SearchBar-module-container"][class*="SearchBar-SearchBar-module-aiMode"] {
  background-color: var(--theme-palette-light) !important;
}

/* AI-mode secondary text (DIS-3585 #4). The AskAnything "Some potential followup
   questions:" heading (.followUpTitle) and the "Responses are generated with AI…"
   disclaimer (.extraDisclaimerToggle) use `var(--theme-palette-soft-dark, <grey>)`.
   The search page mounts inside a BDS SepiidaThemeProvider that RE-EMITS the palette
   at LIGHT values, so inside it that token resolves to the light soft-dark (#363636)
   — dim grey on the dark AI surface. Force the DARK soft-dark value directly (a
   literal, not the shadowed var) so it can't be re-shadowed. The thumbs buttons
   (.upVote/.downVote) keep their own colours — not matched here. */
/* [data-theme="dark"] [class*="followUpTitle"],
[data-theme="dark"] [class*="extraDisclaimerToggle"] {
  color: #F6F9FB !important;
} */

/* AI-mode composer (search "AI mode"). The AskAnything Input is bundled with
   pure-hash CSS-module names from a build our theme source edits don't reach, and
   its gradient-border fill uses `var(--theme-palette-light)` *inside* a
   `linear-gradient()` — which, in that chunk, resolves to the :root (light) value
   and paints the composer white on dark. A literal color in the gradient works
   (the original hardcoded `white` did), so pin the content-box fill layer to the
   instance's dark surface via the Django template value; the neon border layer is
   preserved. Targets the gradient wrapper as the grandchild of the stable
   AISearch inputArea, since the wrapper's own class is an unstable build hash. */
[data-theme="dark"] [class*="AISearch-AISearch-module-inputArea"] > div > div {
  background-image:
    linear-gradient(#292C39, #292C39),
    linear-gradient(90deg, #1686ff 0%, #ad00ff 25%, #1686ff 50%, #ad00ff 75%, #1686ff 100%) !important;
}

/* The composer textarea inherits a baked dark text color from that same
   pure-hash build, so typed text is near-invisible on the dark composer. Unlike
   the gradient fill, a plain `color: var()` resolves correctly, so pin the text
   to the (light-in-dark) role-swapping token. */
[data-theme="dark"] [class*="AISearch-AISearch-module-inputArea"] textarea {
  color: var(--theme-palette-dark) !important;
}

/* Page surface + Bootstrap content containers. The legacy <body> and Bootstrap
   panels/wells hardcode white (Bootstrap defaults / brand LESS), so the token flip
   can't reach them. Re-point the broad content surfaces at the dark neutral ramp:
   page + cards both sit on --theme-palette-light and stay delineated by their
   border (BDS: cards keep their border at every elevation). */
[data-theme="dark"] body {
  background-color: var(--theme-palette-light) !important;
  color: var(--theme-palette-dark) !important;
}

[data-theme="dark"] .panel,
[data-theme="dark"] .panel-default,
[data-theme="dark"] .panel-heading,
[data-theme="dark"] .panel-footer,
[data-theme="dark"] .well,
[data-theme="dark"] .card,
/* generalstyles' `.style-editor-panel` hardcodes `background-color:#ffffff
   !important` (its optional GENERAL_PANEL_BACKGROUND_COLOR override is a light
   authored color too). Most usages also carry `.panel-default` above, but the
   profile bio card (`.container.style-editor-panel`, about.js) does not, so it
   leaks white in dark. Route it through the same dark surface token. */
[data-theme="dark"] .style-editor-panel {
  background-color: var(--theme-palette-light) !important;
  border-color: var(--theme-palette-light-borders) !important;
  color: var(--theme-palette-dark) !important;
}

/* SGP-31879: the chapter-directory map must match the Next.js map in BOTH themes.
   In light mode both apply the configured GOOGLE_MAP_WATER_COLOR / GOOGLE_MAP_LAND_COLOR.
   In dark mode the Next map honors the operator's dark override map
   (HOMEPAGE_DARK_COLOR_OVERRIDES) via buildDarkVarRule; the legacy ChapterMap now
   mirrors that — it re-emits the *_DARK override under [data-theme="dark"] with
   !important from the component itself (see theme/src/js/components/ChapterMap), so
   the dark rule lives with the map rather than here. The previous DIS-3555 rule that
   force-darkened .image-map with `background-color: var(--theme-palette-light)
   !important` was removed earlier so the configured colors show through; nothing to
   add here now. (Marker/foreignObject render on top of the map and are unaffected.) */

/* Chapter directory search dropdown (DIS-3555): the RemoteSearchField dropdown
   hardcodes a #fff panel with a #dfdfdf border, and `.search-result` uses
   `color: inherit`, so in dark mode it renders light-on-light. Flip the panel +
   border to tokens and give the results an explicit text color. Scoped to
   #chapters-page so the shared `.search-drop-down` class on other pages
   (sponsors/people dashboards) is untouched. */
[data-theme="dark"] #chapters-page .search-drop-down {
  background: var(--theme-palette-light) !important;
  border-color: var(--theme-palette-light-borders) !important;
}
[data-theme="dark"] #chapters-page .search-drop-down .search-result {
  color: var(--theme-palette-dark);
}

/* `forms.less` sets a bare `form { color: @gray-dark }` (#333) that doesn't flip,
   so any plain form text — headings/paragraphs that inherit it (e.g. the account
   settings "Account privacy" panel, and login/signup form copy) — goes near-black
   on the dark surface. Re-point the inherited form text at the neutral text token.
   Bare `form` is specificity (0,0,1); this (0,1,1) wins, and inputs/buttons/labels
   with their own color are unaffected. */
[data-theme="dark"] form {
  color: var(--theme-palette-dark);
}

/* Bootstrap form inputs hardcode white. Treat them as inset surfaces (soft-light)
   with light text, same role as the SearchBar input above. */
[data-theme="dark"] .form-control,
[data-theme="dark"] select.form-control,
[data-theme="dark"] textarea.form-control {
  background-color: var(--theme-palette-soft-light) !important;
  border-color: var(--theme-palette-light-borders) !important;
  color: var(--theme-palette-dark) !important;
}

[data-theme="dark"] .form-control::placeholder {
  color: var(--theme-palette-soft-dark) !important;
}

/* Edit Profile <select> caret (Industry / Country / Timezone). The dropdown arrow
   is a Bootstrap .glyphicon overlaid on the field (forms.less), coloured with a
   hardcoded light grey (darken(@gray-lighter,10%)) that blends into the dark field
   surface — so the arrow is invisible in dark. Flip the caret + its divider to
   contrasting tokens. */
[data-theme="dark"] .form-group.select .glyphicon {
  color: var(--theme-palette-dark) !important;
  border-left-color: var(--theme-palette-light-borders) !important;
  /* The caret sits BEHIND the <select> (select has z-index:1). In light mode the
     select bg is transparent so it shows through; in dark the .form-control rule
     makes the select bg opaque, hiding the caret. Lift it above the field. */
  z-index: 2 !important;
}

/* Edit Profile "Interests" (react-widgets multiselect): the typed-input text is a
   hardcoded #333 (react-widgets default), near-invisible on the dark field. Flip
   the input text to the light token (tag chips are already handled below). */
[data-theme="dark"] .interests .rw-input,
[data-theme="dark"] .interests input,
[data-theme="dark"] .rw-multiselect .rw-input {
  color: var(--theme-palette-dark) !important;
}

/* Upcoming-events location search (react-geosuggest `.geosuggest__input`). It is
   not a `.form-control` / `[class*="SearchBar"]`, and its CSS-module rule paints
   the field with --theme-palette-light (= the page surface) so the box vanishes
   into the dark page. Theme it as an inset input (soft-light) with light text,
   matching the .form-control rule above. The exact class + !important wins over
   the BDS/Sepiida runtime styles. */
[data-theme="dark"] .geosuggest__input {
  background-color: var(--theme-palette-soft-light) !important;
  border-color: var(--theme-palette-light-borders) !important;
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] .geosuggest__input::placeholder {
  color: var(--theme-palette-soft-dark) !important;
}

/* Homepage landing hero + location widget. These sections hardcode white and the
   text already flips to white via the token, so in dark mode they render white-on-
   white (invisible). Scope to body.homepage and darken the surfaces. */
[data-theme="dark"] body.homepage .holder,
[data-theme="dark"] body.homepage .intro-text,
[data-theme="dark"] body.homepage .location-widget,
[data-theme="dark"] body.homepage [class*="LocationWidget"],
[data-theme="dark"] body.homepage [class*="IconBlock"] {
  background-color: var(--theme-palette-light) !important;
  color: var(--theme-palette-dark) !important;
}

/* The broad [class*="LocationWidget"] rule above also matches the CSS-module
   class on the search-icon SVG (LocationWidget-styles-iconSearch-*), which painted
   it with the surface bg + dark text — so the glyph went white on a box darker
   than the input. The icon is decorative: keep it transparent (so the input shows
   through) and colored with the brand primary. */
[data-theme="dark"] body.homepage [class*="iconSearch"] {
  background-color: transparent !important;
  color: var(--theme-palette-primary) !important;
}

/* Homepage "groups by region" + location-carousel cards. Unlike the surfaces above,
   these are painted white by per-instance ADMIN style settings in generalstyles.css
   (HOMEPAGE_MAP_GROUPS_BY_REGION_BACKGROUND_COLOR, the carousel card color) rendered
   at high specificity with !important. The real fix is a dark-variant of those admin
   settings (cf. THEME_DARK_PALETTE_*); for the spike we out-specify them at runtime.
   Selectors mirror the admin rules + a [data-theme] prefix so dark wins. */
[data-theme="dark"] .main-dashboard.on-home-page #react-main-chapter-list-root > .holder {
  background-color: var(--theme-palette-light) !important;
}

[data-theme="dark"] .location-widget .location-carousel .slider-frame .slider-list .slider-slide a.icon-block {
  background-color: var(--theme-palette-light) !important;
  color: var(--theme-palette-dark) !important;
}

/* Homepage "Join our community" CTA band (blog.less .homepage .join-cta) paints a
   brand color (@brand-fourth) with hardcoded white text — compiled LESS, no token,
   so the flip can't reach it. Re-point the band surface + its text at the dark
   neutral ramp. The .cta-button keeps its brand (@brand-secondary), per the
   brand-preserved policy. Mirrors the admin selector specificity + !important. */
[data-theme="dark"] body.homepage .join-cta {
  background: var(--theme-palette-light) !important;
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] body.homepage .join-cta .general-h1 {
  color: var(--theme-palette-dark) !important;
}
/* The CTA body text color is the admin setting HOMEPAGE_BOTTOM_CTA_SECTION_BODY_COLOR
   (default var(--theme-palette-light)), emitted via the ID-specificity selector
   `body:not(#main-dashboard).homepage .join-cta p.cta-body` (1,3,2). In dark that
   token resolves to the same neutral as our dark band, so the text disappears.
   Mirror that exact selector (+ [data-theme]) so the light text token wins. */
[data-theme="dark"] body:not(#main-dashboard).homepage .join-cta p.cta-body {
  color: var(--theme-palette-dark) !important;
}

/* Legacy text color. Like the surfaces above, legacy typography color is driven by
   per-instance ADMIN settings (GENERAL_HEADING_FONT_COLOUR, GENERAL_PARAGRAPH_FONT_
   COLOR, …) baked as fixed dark values with !important — no dark variant — so in dark
   mode headings collapse into the bg and body grays drop below contrast. Re-point the
   "general" typography families at the light neutral ramp. Paragraph rules carry ID-
   level specificity via body:not(#main-dashboard), so the override mirrors that. The
   real fix is dark-variant admin color settings (cf. THEME_DARK_PALETTE_*). */
[data-theme="dark"] .general-h1,
[data-theme="dark"] .general-h1 > a,
[data-theme="dark"] .general-body h1,
[data-theme="dark"] .general-body h2,
[data-theme="dark"] .general-body--color h1,
[data-theme="dark"] .general-body--color h2,
[data-theme="dark"] .section-header,
[data-theme="dark"] .chapters-title,
[data-theme="dark"] .page-title {
  color: var(--theme-palette-dark) !important;
}

[data-theme="dark"] body:not(#main-dashboard) .general-body,
[data-theme="dark"] body:not(#main-dashboard) .general-body--color,
[data-theme="dark"] body:not(#main-dashboard) .general-body--color h4,
[data-theme="dark"] .about-message {
  color: var(--theme-palette-soft-dark) !important;
}

[data-theme="dark"] .date,
[data-theme="dark"] .post-timestamp,
[data-theme="dark"] .blog-live-author,
[data-theme="dark"] .blog-live-time {
  color: var(--theme-palette-light-borders) !important;
}

/* My Tickets (profile event listing): the date + the "Please Un-RSVP" prompt/link
   inherited the low-contrast light-borders token (date) or an unset muted color
   (ticket row), reading as washed-out grey on the dark card. Route them to the
   readable muted-text token used by body copy. Higher specificity than the generic
   [data-theme] .date rule above, so it wins there without touching other timestamps. */
[data-theme="dark"] .event-listing .event-details .date,
[data-theme="dark"] .event-listing .event-details .ticket,
[data-theme="dark"] .event-listing .event-details .ticket a {
  color: var(--theme-palette-soft-dark) !important;
}

/* High-specificity admin color rules need same-or-higher specificity to override.
   The blocks below mirror the exact generalstyles.css / homepage admin selectors
   (which carry IDs and/or :not(#main-dashboard) and !important) with a [data-theme]
   prefix so the dark override wins on specificity, not just source order. These exist
   because per-widget admin color settings have no dark variant — the scalable fix is
   to add dark-variant admin settings, not to mirror every selector here. */

/* Homepage intro hero (HOMEPAGE intro title/paragraph) */
[data-theme="dark"] .intro-text .section-header,
[data-theme="dark"] .intro-text .general-h1 {
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] .intro-text .about-message {
  color: var(--theme-palette-soft-dark) !important;
}

/* Homepage "groups by region" heading + region cards */
[data-theme="dark"] .main-dashboard.on-home-page #react-main-chapter-list-root > .holder .chapters-title {
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] #react-main-chapter-list-root .row.regions-list .chapter-item strong {
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] #react-main-chapter-list-root .row.regions-list .chapter-item span {
  color: var(--theme-palette-light-borders) !important;
}

/* General tabs (List / Calendar) inherit the general-body link color; mirror that
   selector chain + one extra class so the dark override out-specifies it. */
[data-theme="dark"] body:not(#main-dashboard) .general-body a.general-tab:not(.general-body--exclude):not(.btn),
[data-theme="dark"] body:not(#main-dashboard) .general-body--color a.general-tab:not(.general-body--exclude):not(.btn) {
  color: var(--theme-palette-light-borders) !important;
}

/* Account settings tabs (Privacy / Change password / Delete account) AND user
   profile tabs (Profile / Rewards / Discussions / My tickets / Updates / API key).
   The shared .general-tab rule above pins them to --theme-palette-light-borders —
   too dim to read. Scope a higher-specificity override to the settings .tablist and
   the profile .navbar-right (each compound with .general-body--color on the same
   <ul>), leaving the List/Calendar general-tabs untouched: inactive readable-muted,
   active full-contrast. */
[data-theme="dark"] body:not(#main-dashboard) .general-body--color.tablist a.general-tab:not(.general-body--exclude):not(.btn),
[data-theme="dark"] body:not(#main-dashboard) .general-body--color.navbar-right a.general-tab:not(.general-body--exclude):not(.btn) {
  color: var(--theme-palette-soft-dark) !important;
}
[data-theme="dark"] body:not(#main-dashboard) .general-body--color.tablist li.active a.general-tab:not(.general-body--exclude):not(.btn),
[data-theme="dark"] body:not(#main-dashboard) .general-body--color.navbar-right li.active a.general-tab:not(.general-body--exclude):not(.btn) {
  color: var(--theme-palette-dark) !important;
}

/* Account settings, "Account privacy": the rmwc/Material Switch bakes its "Public
   profile" label at rgba(0,0,0,.87) (black), unreadable on dark. Flip to the light
   text token. */
[data-theme="dark"] .profile_switch label,
[data-theme="dark"] .privacy_switch label {
  color: var(--theme-palette-dark) !important;
}

/* Primary buttons (Save / Change password / Delete account — and every primary
   button site-wide). generalstyles.css pins their label to var(--theme-palette-light)
   !important via an ID-boosted selector (body:not(#main-dashboard) .btn.btn-primary…),
   which is white in light but a dark #292C39 in dark — poor contrast on the constant
   brand-blue fill. Mirror that exact selector under [data-theme="dark"] (one extra
   attribute → out-specifies it) to flip the label to the light-in-dark token. */
[data-theme="dark"] body:not(#main-dashboard) .btn.btn-primary:not(.dropdown-toggle):not(.grey) {
  color: var(--theme-palette-dark) !important;
}

/* Chapters directory city/region cards: the hover background is compiled LESS
   (dashboard.less `.chapters-panel .chapter-item:hover { background: @dashboard-
   gray-lightest }`), a hardcoded light gray that doesn't flip — so on dark it goes
   white while the card title (flipped to a light token) stays white → invisible on
   hover (DM-027). Re-point the hover surface at the soft-light dark token. */
[data-theme="dark"] .chapters-panel .chapter-item:hover {
  background-color: var(--theme-palette-soft-light) !important;
}

/* Events page (#react-upcoming-events-widget-root): the react-big-calendar grid
   and the react-widgets Event-types/tags selects are library defaults with
   hardcoded light surfaces (not token-driven), so they stay white in dark. Re-point
   them at the dark neutral ramp. The header row (.rbc-header) is already dark via
   the component LESS; the city search is geosuggest (themed above). */
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-toolbar,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-month-view,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-time-view,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-month-row,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-day-bg,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-time-content,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-time-header-content,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-timeslot-group {
  background-color: var(--theme-palette-light) !important;
  border-color: var(--theme-palette-light-borders) !important;
}
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-off-range-bg {
  background-color: var(--theme-palette-soft-light) !important;
}
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-off-range {
  color: var(--theme-palette-soft-dark) !important;
}
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-today {
  background-color: var(--theme-palette-soft-light) !important;
}
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-date-cell,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-button-link,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-toolbar,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-toolbar-label,
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-toolbar button {
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] #react-upcoming-events-widget-root .rbc-calendar .rbc-btn-group button.rbc-active {
  background-color: var(--theme-palette-soft-light) !important;
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] #react-upcoming-events-widget-root .rw-widget-input,
[data-theme="dark"] #react-upcoming-events-widget-root .rw-widget-picker,
[data-theme="dark"] #react-upcoming-events-widget-root .rw-dropdownlist {
  background-color: var(--theme-palette-soft-light) !important;
  color: var(--theme-palette-dark) !important;
}
/* The popup PANEL is deliberately --theme-palette-light rather than the
   --theme-palette-soft-light used for the closed inputs above. Every hover colour that
   can reach an option is one of `#555`, GENERAL_BRAND_PRIMARY_COLOR, or the value of
   GENERAL_HOVER_SEARCH_DROPDOWN_ITEM_BACKGROUND_COLOR — and that last setting is a
   palette token on some instances (demo stores --theme-palette-soft-light). Painting the
   panel soft-light there makes the hovered option exactly the same colour as the panel
   behind it, silently erasing the hover cue. --theme-palette-light contrasts against all
   three. The caret is repainted to match: DropdownMultiselect/styles.less draws it with a
   soft-light border-bottom to match the panel it assumed. DIS-3624. */
[data-theme="dark"] #react-upcoming-events-widget-root .rw-popup {
  background-color: var(--theme-palette-light) !important;
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] #react-upcoming-events-widget-root .rw-popup.rw-widget::before {
  border-bottom-color: var(--theme-palette-light);
}
/* The events search input + select borders are painted by ID-specificity source
   rules (#react-upcoming-events-widget-root …) that outrank a bare [data-theme]
   selector, so mirror those exact selectors to let the tokens win. The select
   nests a bordered outer .form-control.rw-widget around a bordered inner
   .rw-widget-container; color the outer, zero the inner so there is one border. */
[data-theme="dark"] #react-upcoming-events-widget-root .geosuggest__input {
  background-color: var(--theme-palette-soft-light) !important;
  /* Drop the input's own border so only the wrapper's border shows — the inner
     border sat inside the wrapper with a larger radius (double outline). Match the
     wrapper's 12px radius so the fill lines up with the .geosuggest__input-wrapper
     border (the input was a 100px pill inside a 12px wrapper). */
  border-color: transparent !important;
  border-radius: 12px !important;
  color: var(--theme-palette-dark) !important;
}
/* The .geosuggest__input-wrapper border is a hardcoded light gray (#E5E5E5) that
   doesn't flip — repoint it at the shared borders token so it matches the selects. */
[data-theme="dark"] #react-upcoming-events-widget-root .geosuggest__input-wrapper {
  border-color: var(--theme-palette-light-borders) !important;
}
[data-theme="dark"] #react-upcoming-events-widget-root .form-control.rw-widget {
  border-color: var(--theme-palette-light-borders) !important;
}
[data-theme="dark"] #react-upcoming-events-widget-root .form-control.rw-widget .rw-widget-container:not(.BDS-component) {
  border-color: transparent !important;
}
/* The dropdown OPTION SURFACES are hardcoded `#fff` in the component LESS
   (UpcomingEventsWidget/styles.less `ul > li` and `.geosuggest__item/__suggests`),
   while the option TEXT is painted by an unscoped, config-driven `color: … !important`
   rule in generalstyles.css (~:1469) fed by the GENERAL_SEARCH_DROPDOWN_ITEM_FONT_COLOR
   setting, whose stored value is a palette token (e.g. var(--theme-palette-soft-dark)).
   So the text flips light in dark mode while the panel stays white: white-on-white.
   Flip the surfaces so the palette-driven text reads. The options go TRANSPARENT rather
   than --theme-palette-light because .rw-popup is already painted (above) and the focus
   rule below uses --theme-palette-light — painting both the same would erase the focus
   cue. (The setting name is written bare above on purpose: this file is rendered
   through pystache, so a double-brace tag here — even inside a comment — would be
   interpolated away.)

   Scoped to :not(:hover) deliberately. Two different hover rules reach these options —
   generalstyles.css (~:1484, #555 or the brand colour with #fff text) and
   DropdownMultiselect/styles.less (var(--theme-palette-light)) — and both are already
   legible in either theme. Neither carries !important, so an unrestricted rule here
   outranks them on ID specificity and silently deletes the hover cue. DIS-3624. */
[data-theme="dark"] #react-upcoming-events-widget-root .rw-list-option:not(:hover) {
  background-color: transparent !important;
  color: var(--theme-palette-dark) !important;
}
/* react-widgets puts .rw-state-focus on the keyboard cursor option (the first one, as
   soon as the popup opens). It must not reuse --theme-palette-light, which now paints the
   panel itself — soft-light keeps the cursor legible and matches the hover treatment. */
[data-theme="dark"] #react-upcoming-events-widget-root .rw-list-option.rw-state-focus {
  background-color: var(--theme-palette-soft-light) !important;
}
/* Each event-type option carries a checkbox drawn from check_radio_sheet.png, a sprite
   whose tick is baked at #333 against a TRANSPARENT interior — there is no glyph or text
   node here, so the tick cannot be recoloured with CSS. In light mode that transparency
   shows the white panel through, so the dark tick reads; on the now-dark panel it is
   black-on-black and the option looks unselected even when it is checked. Repainting just
   the interior light restores exactly the light-mode rendering, so no dark-variant asset
   is needed. (filter: invert() was rejected: it would also flip the #bcbcbc outline dark
   and hide the empty box instead.) DIS-3624. */
[data-theme="dark"] #react-upcoming-events-widget-root .rw-list-option .styled-input.ui-element {
  background-color: var(--theme-palette-dark);
  /* Mirrors the twin checkbox repaint in new-dashboard.less:1211, which uses the
     --dashboard-theme-radius-xs token. That token is defined only in the dashboard
     :root (new-dashboard.css / client_dashboard.html), which this public events page
     never loads — so the 3px fallback is what actually renders here. Referencing the
     token keeps the two repaints textually in sync without depending on it resolving. */
  border-radius: var(--dashboard-theme-radius-xs, 3px);
}
/* City/region search (react-geosuggest) renders its own in-tree <ul> — theme.css
   previously styled only the input, so the suggestion panel kept its light LESS hex. */
[data-theme="dark"] #react-upcoming-events-widget-root .geosuggest__suggests {
  background-color: var(--theme-palette-light) !important;
  border-color: var(--theme-palette-light-borders) !important;
}
/* Same guard as .rw-list-option above, for the same reason: an unguarded
   `transparent !important` at ID specificity (1,2,0) out-!importants the geosuggest
   hover/active rule (generalstyles.css ~:1480, (0,4,1)) and paints the hovered /
   keyboard-active suggestion the same colour as the panel behind it — erasing the
   cue. Exclude .geosuggest__item--active too: it's a sibling class, so a bare
   :not(:hover) wouldn't cover keyboard navigation. Pin the text colour as well (as
   .rw-list-option does) so a tenant that stored a literal in
   GENERAL_SEARCH_DROPDOWN_ITEM_FONT_COLOR doesn't get dark-on-dark on the darkened
   panel. DIS-3624. */
[data-theme="dark"] #react-upcoming-events-widget-root
  .geosuggest__item:not(:hover):not(.geosuggest__item--active) {
  background-color: transparent !important;
  color: var(--theme-palette-dark) !important;
}
/* The "powered by Google" attribution badge (global.less ~:1096) uses
   powered_by_google_on_white.png — a 144x18 sprite that is 66% TRANSPARENT with dark
   grey "powered by" lettering baked in as pixels (there is no text node here, so the
   lettering cannot be restyled with CSS). On a dark panel that grey lettering
   disappears into the background and only the coloured Google logo survives, which
   fails Google's attribution requirement.

   Swap to the non-white variant, which carries the same logo with WHITE lettering.
   Only the image changes — position/size still come from the global.less rule.

   Scoped to the two geosuggest panels this PR actually darkens, by mount ID, rather
   than root-scoped on [data-theme="dark"]. The white-lettering sprite is correct ONLY
   where the panel behind it is dark:
   - #react-upcoming-events-widget-root — the events-page panel, painted
     --theme-palette-light by the .geosuggest__suggests rule above.
   - #react-location-widget-root — the homepage / section location widget, whose
     LocationWidget/styles.less li background is var(--theme-palette-light), which flips
     dark. The bare id is the stable hook: .location-widget is only an optional
     extra_class (custom_mezzanine_upcoming_events_w_filters.html), and the ebay/uipath
     mounts (clients/{ebay,uipath}/src/js/*.js) query the id with no class.
   A bare [data-theme="dark"] selector would also reach a THIRD geosuggest panel —
   ReadMoreSidebar (#react-read-more-sidebar-root, index.html gated by
   SHOW_READ_MORE_SIDEBAR, on for startupgrind) — whose rows are a hardcoded white
   `li { background: #fff }` (read_more_sidebar.less:44) that this PR never darkens.
   White lettering on that still-white panel would erase the attribution there, moving
   the exact bug this rule fixes rather than eliminating it, so it is excluded. (C-H1)

   Rejected: `filter: invert()` would recolour the Google logo itself (brand
   violation); painting a white chip behind the sprite reads as a sticker on the dark
   panel and clips the logo. Lives here rather than in global.less because that file's
   pre-existing `media-query-no-invalid` violations would be surfaced (and
   destructively auto-"fixed") by the changed-files stylelint run. DIS-3624. */
[data-theme="dark"] #react-upcoming-events-widget-root
  .geosuggest__suggests-wrapper
  .geosuggest__suggests
  li:last-child::after,
[data-theme="dark"] #react-location-widget-root
  .geosuggest__suggests-wrapper
  .geosuggest__suggests
  li:last-child::after {
  background-image: url("/static/images/powered_by_google_on_non_white.png");
}

/* swal2 error/confirmation modals (library default white panel) — app-wide, not
   scoped to the events page. The brand OK button (.swal2-confirm) stays branded. */
[data-theme="dark"] .swal2-modal {
  background-color: var(--theme-palette-light) !important;
}
[data-theme="dark"] .swal2-modal .swal2-title,
[data-theme="dark"] .swal2-modal .swal2-content {
  color: var(--theme-palette-dark) !important;
}

/* Blog post titles (compiled brand gray, not admin-driven) */
[data-theme="dark"] .blog-posts .blog-live-title > a,
[data-theme="dark"] .blog-live-title > a {
  color: var(--theme-palette-dark) !important;
}

/* Bootstrap dropdown panels — the user-menu dropdown and the per-item ⋮ (kebab)
   menus (notifications, etc.) render a Bootstrap `.dropdown-menu` panel that is
   compiled-LESS white (Bootstrap default) and is not reached by the chrome/token
   overrides above, so it's white-on-white in dark (DM-023, DM-030). Re-point the
   panel, its items, hover state and dividers at the dark neutral ramp. */
[data-theme="dark"] .dropdown-menu {
  background-color: var(--theme-palette-light) !important;
  border-color: var(--theme-palette-light-borders) !important;
}
[data-theme="dark"] .dropdown-menu > li > a,
[data-theme="dark"] .dropdown-menu > li > button,
[data-theme="dark"] .dropdown-menu li > a,
[data-theme="dark"] .dropdown-menu [class*="Text"] {
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] .dropdown-menu > li > a:hover,
[data-theme="dark"] .dropdown-menu > li > a:focus,
[data-theme="dark"] .dropdown-menu > li > button:hover,
[data-theme="dark"] .dropdown-menu > li > button:focus {
  background-color: var(--theme-palette-soft-light) !important;
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] .dropdown-menu .divider {
  background-color: var(--theme-palette-light-borders) !important;
}

/* Notifications dropdown (BDS NotificationsMenu island — the bell popover, DIS-3585).
   The BDS component ships hard-coded LIGHT hex (panel #fff, chrome borders #d3dce4,
   unread/hover band #f6f9fb, message text #3c4153) and reads none of the --Color*
   tokens, so the whole popover renders as a white box with dark text over the dark
   UI. This block is a 1:1 mirror of next/src/app/dark-overrides.css (the /next bell
   dropdown uses the SAME BDS component) so the two match. The broad __unread match is
   intentional — it also re-points the unread DOT fill to the soft token, giving the
   same subtle ring /next shows instead of a hard red dot. Substring class matches
   survive the BDS build-hash suffixes (…_aggpl / …_47za0). */
[data-theme="dark"] [class*="NotificationsMenuItem-styles__unread"],
[data-theme="dark"] [class*="NotificationsMenuItem-styles__interactive"]:hover,
[data-theme="dark"] [class*="NotificationsMenu-styles__viewAll"]:hover {
  background: var(--theme-palette-soft-light) !important;
}
[data-theme="dark"] [class*="NotificationsMenuItem-styles__body"] {
  color: var(--theme-palette-dark) !important;
}
[data-theme="dark"] [class*="NotificationsMenu-styles__menu"] {
  background: var(--theme-palette-light) !important;
  border-color: var(--theme-palette-light-borders) !important;
}
[data-theme="dark"] [class*="NotificationsMenu-styles__header_"] {
  border-bottom-color: var(--theme-palette-light-borders) !important;
}
[data-theme="dark"] [class*="NotificationsMenu-styles__footer"] {
  border-top-color: var(--theme-palette-light-borders) !important;
}

/* Django-ONLY layout fix (no /next counterpart). The bell popover mounts INSIDE the
   navbar (`li.notifications-menu-item`), so legacy navbar/heading descendant CSS
   cascades into the BDS NotificationsMenu and breaks its header: the title (a BDS
   <h4>) drops below the "mark all as read" action and a large empty band opens at the
   top of the panel — the misaligned/oversized header seen only on the Django island
   (/next renders the same component with no legacy CSS around it). Re-assert the BDS
   header's intended flex row and collapse the inherited heading spacing so it packs
   like /next. Mode-agnostic — the layout bug exists in both light and dark. */
[class*="NotificationsMenu-styles__header_"] {
  display: flex !important;
  align-items: center !important;
  justify-content: space-between !important;
  padding: 16px !important;
}
[class*="NotificationsMenu-styles__header_"] h1,
[class*="NotificationsMenu-styles__header_"] h2,
[class*="NotificationsMenu-styles__header_"] h3,
[class*="NotificationsMenu-styles__header_"] h4,
[class*="NotificationsMenu-styles__header_"] h5,
[class*="NotificationsMenu-styles__header_"] h6 {
  margin: 0 !important;
  line-height: 1.2 !important;
}
/* Both header children (title + the mark-all/gear group) on one centered row. */
[class*="NotificationsMenu-styles__header_"] > * {
  align-self: center !important;
  margin-top: 0 !important;
  margin-bottom: 0 !important;
}

/* Match /next's panel width: /next passes style width min(380px, 92vw); the Django
   island passes no width so BDS falls back to its 330px default, making the panel
   visibly narrower. Mode-agnostic. */
[class*="NotificationsMenu-styles__menu"] {
  width: min(380px, 92vw) !important;
}

/* "View all notifications" footer link: BDS renders it as <Text color="primary">,
   which resolves --text-color-primary — a var the Django dark block never sets, so
   it fell back to white instead of the brand colour /next shows. Point it at the
   brand primary token (defined in both modes). */
/* Must out-specify the navbar's blanket dark rule
   `[data-theme="dark"] header.navs [class*="Text"]` (0,3,1, !important) that paints
   every header control white — so scope under header.navs AND match the Text node. */
[data-theme="dark"] header.navs [data-testid="notifications-view-all"],
[data-theme="dark"] header.navs [data-testid="notifications-view-all"] *,
[data-theme="dark"] header.navs [data-testid="notifications-view-all"] [class*="Text"] {
  color: #1DE4EB !important;
}

/* Bell trigger backdrop (DIS-3585). The trigger paints a --ColorSoftLight circle
   behind the bell on hover/open. On /next's header that elevation reads invisible in
   dark; on the legacy navbar it shows as a light halo /next doesn't have. Zero it in
   dark (light mode keeps the affordance). The class is added in NotificationsDropdown.js;
   the !important beats the element's inline background. */
[data-theme="dark"] .notifications-bell-backdrop {
  background-color: transparent !important;
}

/* Dark-mode toggle in the user menu (pages/menus/dark-mode-toggle.html). A visual
   twin of the Next.js header's ThemeToggle (label + Sun · switch · Moon) so the two
   headers match. Replicates ThemeToggle.module.scss with the --theme-palette-* tokens
   (1:1 with the Next version's --Color* tokens) and drives state from <html data-theme>
   instead of React. Not theme-scoped — it's a real control that renders in both modes;
   the [data-theme="dark"] rules below flip its active state. */
.top-nav-dragon .main-menu.dropdown-menu > li.theme-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 8px;
  color: var(--theme-palette-soft-dark);
  font-size: 14px;
  font-weight: 400;
  line-height: 136%;
}

.theme-toggle__label {
  flex: 1;
}
.theme-toggle__label--dark {
  display: none;
}
[data-theme="dark"] .theme-toggle__label--light {
  display: none;
}
[data-theme="dark"] .theme-toggle__label--dark {
  display: block;
}

.theme-toggle__control {
  display: flex;
  flex: none;
  align-items: center;
  gap: 8px;
}

.theme-toggle__icon {
  width: 16px;
  height: 16px;
  color: var(--theme-palette-soft-dark);
  opacity: 0.4;
  transition: opacity 120ms linear, color 120ms linear;
}
/* Sun is the active icon in light, Moon in dark. */
.theme-toggle__icon--sun {
  color: var(--theme-palette-primary);
  opacity: 1;
}
[data-theme="dark"] .theme-toggle__icon--sun {
  color: var(--theme-palette-soft-dark);
  opacity: 0.4;
}
[data-theme="dark"] .theme-toggle__icon--moon {
  color: var(--theme-palette-primary);
  opacity: 1;
}

.theme-toggle__switch {
  position: relative;
  width: 38px;
  height: 22px;
  padding: 0;
  border: 1px solid var(--theme-palette-light-borders);
  border-radius: 999px;
  background-color: var(--theme-palette-soft-light);
  cursor: pointer;
  transition: background-color 160ms ease, border-color 160ms ease;
}
[data-theme="dark"] .theme-toggle__switch {
  border-color: var(--theme-palette-primary);
  background-color: var(--theme-palette-primary);
}
.theme-toggle__switch:focus-visible {
  outline: 2px solid var(--theme-palette-primary);
  outline-offset: 2px;
}

.theme-toggle__knob {
  position: absolute;
  top: 50%;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background-color: var(--theme-palette-light);
  box-shadow: 0 1px 2px rgb(0 0 0 / 25%);
  transform: translateY(-50%);
  transition: transform 160ms ease;
}
[data-theme="dark"] .theme-toggle__knob {
  transform: translate(16px, -50%);
}

/* --- DIS-3613 logged-out icon-only toggle (top bar) ---
   Reuses the .theme-toggle / .theme-toggle__switch hooks (so the base.html controller
   wires the click) but drops the dropdown pill/knob/label styling. Two grid-stacked
   icons reflect the current theme (sun in light, moon in dark); the visible one is
   chosen by opacity/transform on [data-theme], animating on toggle (BDS 2.0
   bds-theme-toggle style — legacy has no next-themes suppression, so a transition is
   reliable here). Desktop matches the navbar link vertical rhythm; mobile centers
   within the header actions row. */
.theme-toggle--compact {
  display: inline-flex;
  align-items: center;
  padding: 0;
  margin: 0;
}
.theme-toggle--compact .theme-toggle__switch {
  display: inline-grid;
  place-items: center;
  /* Reset the fixed 38x22 pill size the base .theme-toggle__switch sets (that pill
     height is why the mobile icon overflowed and sat below the row); size to the icon
     instead. Desktop re-stretches height to 100% of the row below. */
  width: auto;
  height: auto;
  padding: 8px;
  border: none;
  border-radius: 9999px;
  background: none;
  color: inherit;
  cursor: pointer;
}
.theme-toggle--compact .theme-toggle__icon {
  grid-area: 1 / 1;
  width: 20px;
  height: 20px;
  color: inherit;
  transition-property: opacity, transform;
  transition-duration: 0.2s;
  transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
/* Light theme: sun in, moon rotated out. */
.theme-toggle--compact .theme-toggle__icon--sun {
  opacity: 1;
  transform: rotate(0) scale(1);
}
.theme-toggle--compact .theme-toggle__icon--moon {
  opacity: 0;
  transform: rotate(90deg) scale(0.4);
}
/* Dark theme: sun rotated out, moon in. */
[data-theme="dark"] .theme-toggle--compact .theme-toggle__icon--sun {
  opacity: 0;
  transform: rotate(-90deg) scale(0.4);
}
[data-theme="dark"] .theme-toggle--compact .theme-toggle__icon--moon {
  opacity: 1;
  transform: rotate(0) scale(1);
}
/* Desktop: the nav row (.top-nav-dragon) stretches every item to the full row height.
   A navbar rule keeps the <li> as a block and floats the button to the top, so instead
   of fighting it we make the button fill the li's full height; its own grid then
   centers the icon on the sibling nav links' vertical center. Scoped to the desktop li
   (:not(.mobile-header-action)) so the mobile toggle is unaffected. */
.top-nav-dragon .theme-toggle--compact:not(.mobile-header-action) .theme-toggle__switch {
  height: 100%;
}
/* Mobile: the .mobile-header-actions flex row already centers its items, so the mobile
   toggle needs nothing extra here. */
@media (prefers-reduced-motion: reduce) {
  .theme-toggle--compact .theme-toggle__icon {
    transition: none;
  }
}

/* --- DIS-3555 legacy dark-mode residuals (Account settings + Profile / Edit profile) ---
   These surfaces use compiled-LESS hex (@gray-lighter/@beige/#333), Bootstrap defaults or
   third-party (react-widgets, Material) chrome — none read the palette tokens, so they stay
   light in dark mode. Re-point them to the role-swapping --theme-palette-* tokens. */

/* Profile tabs (P1): .nav-underscore resting color (@gray-lighter) + active color don't flip.
   The active underline keeps @brand-primary (brand color, intentionally unchanged). */
[data-theme="dark"] .nav-underscore li a {
  color: var(--theme-palette-soft-dark);
}
[data-theme="dark"] .nav-underscore li.active a,
[data-theme="dark"] .no-touch .nav-underscore li a:hover,
[data-theme="dark"] .nav-underscore li a.active {
  color: var(--theme-palette-dark);
}

/* Profile → Updates "Global" checkbox is an MUI (v4) Checkbox whose unchecked SVG
   box uses rgba(0,0,0,.54) (black) — invisible on dark. Lighten the unchecked box to
   a visible token; the checked state keeps MUI's primary (brand) fill. */
[data-theme="dark"] .MuiCheckbox-root:not(.Mui-checked),
[data-theme="dark"] .MuiCheckbox-root:not(.Mui-checked) .MuiSvgIcon-root {
  color: var(--theme-palette-soft-dark) !important;
}

/* Profile → My tickets (DIS-3555 P6). Ticket cards use hardcoded text colors that
   don't flip: `.event-title a { color:#333 }` (profile.less) and the surrounding
   card copy. The `.style-editor-card` surface is a Bootstrap `.panel-default`, so it
   already flips via the panel rule above; here we only re-point the static text. */
[data-theme="dark"] .style-editor-card,
[data-theme="dark"] .style-editor-card .event-title,
[data-theme="dark"] .style-editor-card .event-title a,
[data-theme="dark"] .event-title,
[data-theme="dark"] .event-title a {
  /* !important: profile.less nests `.event-title a { color:#333 }` under a deep
     context that out-specifies a plain override, so force the flip. */
  color: var(--theme-palette-dark) !important;
}

/* Tag chips — react-widgets multiselect (Account tags A1a, Edit-profile interests E2):
   hardcoded #f4f4f4 chip bg, light widget container.
   This rule only lands the `color` half: MultiselectInput.less compiles to a (0,5,1)
   selector that beats this (0,2,1) on `background-color`, so the chip background is
   flipped at source in that module instead (DIS-3621). The remove button needs no rule
   — react-widgets sets `color: inherit` on `.rw-multiselect-tag-btn`, so it follows the
   `color` below. */
[data-theme="dark"] .rw-multiselect-taglist > li {
  background-color: var(--theme-palette-soft-light);
  color: var(--theme-palette-dark);
}
[data-theme="dark"] .rw-widget-container:not(.BDS-component) {
  background-color: var(--theme-palette-light);
  border-color: var(--theme-palette-light-borders);
}
/* Edit-profile "Interests" tag field (react-widgets Multiselect). The bright white
   line on dark is the vendor `.rw-widget-container { border: #ccc 1px solid }` — the
   Multiselect here gets no `.form-control` class (MultiselectInput puts className on
   its wrapper div, not the widget), so `.rw-widget` is `border: none` and the OUTER
   selectors below never paint it. Route the actual bordered inner container (and the
   `.form-control`/focus variants used by other legacy rw-widgets) to the dark border
   token. `:not(.BDS-component)` leaves BDS widgets alone; Upcoming-events keeps its
   own #react-upcoming-events-widget-root-scoped border, which still wins there. */
[data-theme="dark"] .rw-multiselect .rw-widget-container:not(.BDS-component),
[data-theme="dark"] .form-control.rw-widget,
[data-theme="dark"] .rw-widget,
[data-theme="dark"] .rw-state-focus .rw-widget-picker {
  border-color: var(--theme-palette-light-borders) !important;
}

/* Edit-profile "@" handle prefix (E3): Bootstrap .input-group-addon default #eee/#ccc. */
[data-theme="dark"] .input-group-addon {
  background-color: var(--theme-palette-soft-light);
  border-color: var(--theme-palette-light-borders);
  color: var(--theme-palette-dark);
}

/* Edit-profile banner upload area (E1): hardcoded @gray-lighter background. */
[data-theme="dark"] .profile-edit .profile-banner-upload {
  background-color: var(--theme-palette-soft-light);
}

/* Profile Updates (P7): selected panel heading @beige background. */
[data-theme="dark"] .updates .panel-heading.selected {
  background-color: var(--theme-palette-soft-light);
}

/* Profile My-tickets (P6): Bootstrap .style-editor-card surface + hardcoded #333 event title. */
[data-theme="dark"] .style-editor-card {
  background-color: var(--theme-palette-light);
  border-color: var(--theme-palette-light-borders);
  color: var(--theme-palette-dark);
}
[data-theme="dark"] .event-title a {
  color: var(--theme-palette-dark);
}

/* Privacy toggle (A1b): rmwc/Material switch unchecked track (@gray-lighter). The checked
   track/knob keep their brand color (intentionally unchanged). */
[data-theme="dark"] .mdc-switch:not(.mdc-switch--checked) .mdc-switch__track {
  background-color: var(--theme-palette-dark-borders);
}
