/* Theme switcher rendering plan
   ─────────────────────────────
   • The shared header embeds it inside `<li class="navbar-theme-switcher">`
     so the toggle lives in the navbar by default.
   • `layout.jinja2` also includes a floating copy at body level as a
     fallback for projects whose header override drops the navbar version
     (e.g. devdeck.dev has its own header.jinja2 without the navbar slot).
   • When BOTH copies are present in the DOM (because the project uses the
     shared header AND the floating fallback in layout), the floating one
     is hidden so only the navbar copy renders.
   • Project overrides of `theme_switcher.jinja2` (e.g. eduloo's pomodoro
     variant with `position: fixed !important`) continue to work — their
     CSS can pin the toggle wherever they want regardless of which slot
     emitted it. */

.theme-switcher {
  position: fixed;
  top: calc(var(--navbar-offset) + 8px);
  right: 12px;
  z-index: 20000;
}

/* When inside the navbar slot, sit inline (project overrides can still
   force `position: fixed !important` to pull it back to floating). */
.navbar-theme-switcher {
  display: inline-flex;
  align-items: center;
  margin-left: 4px;
}

.navbar-theme-switcher .theme-switcher {
  position: static;
  top: auto;
  right: auto;
  z-index: auto;
  display: inline-flex;
  align-items: center;
}

/* If the page contains the navbar slot, hide the body-level floating
   fallback so we don't render two copies on projects that use both. */
body:has(.navbar-theme-switcher) > .theme-switcher {
  display: none;
}

@media (max-width: 750px) {
  .theme-switcher {
    display: none;
  }
}
.theme-toggle-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  min-width: 36px;
  min-height: 36px;
  padding: 0;
  border-radius: 10px;
  position: relative;
  z-index: 1;
  margin-top: 10px;
  background: transparent;
  border: none;
  box-shadow: none;
  cursor: pointer;
  transition:
    background 0.18s ease,
    transform 0.12s ease;
  font-size: 22px;
}
.theme-toggle-button:hover {
  background: rgba(128, 128, 128, 0.12);
  transform: none;
  box-shadow: none;
  border: none;
}
.theme-toggle-button:active {
  transform: scale(0.9);
  background: rgba(128, 128, 128, 0.18);
}
.theme-toggle-button:focus {
  outline: none;
  box-shadow: none;
}
body.theme-dark .theme-toggle-button {
  color: #c0bcb8;
}
body.theme-light .theme-toggle-button {
  color: #2d2926;
  background: rgba(255, 255, 255, 0.75);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: 0 1px 6px rgba(45, 41, 38, 0.14);
}
body.theme-light .theme-toggle-button:hover {
  background: rgba(255, 255, 255, 0.92);
  box-shadow: 0 2px 10px rgba(45, 41, 38, 0.18);
}
.theme-icon {
  display: inline-block;
  line-height: 1;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) rotate(0deg) scale(1);
  transition:
    opacity 0.25s ease,
    transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* Dark theme: moon visible, sun hidden behind */
.theme-icon.fa-moon {
  opacity: 1;
}
.theme-icon.fa-sun {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(90deg) scale(0.6);
}
/* Light theme: sun visible, moon rotated away */
body.theme-light .theme-icon.fa-moon {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(-90deg) scale(0.6);
}
body.theme-light .theme-icon.fa-sun {
  opacity: 1;
  transform: translate(-50%, -50%) rotate(0deg) scale(1);
}
/* The 'auto' preference has no icon of its own: it is the silent default for
   users who never chose, and shows as whichever appearance it resolves to,
   driven by the body theme class above. */
/* Snappier easing during active switch */
body.theme-switching .theme-icon {
  transition:
    opacity 0.2s ease,
    transform 0.28s cubic-bezier(0.55, 0, 0.45, 1);
}

/*
 * Freeze every other transition for the length of the switch.
 *
 * Components that transition their own colours (buttons, cards, the hero CTAs)
 * otherwise start tweening from the old palette to the new one at the moment
 * the theme class flips. That tween is still running as the veil lifts, so the
 * element visibly flashes through an in-between colour after everything else
 * has already settled. Cutting transitions makes the repaint instantaneous and
 * completely hidden behind the veil.
 *
 * The theme icon is exempt (it is *meant* to animate) and so is the veil, which
 * is driven by the Web Animations API rather than a CSS transition.
 */
body.theme-switching *:not(.theme-icon):not(.theme-veil),
body.theme-switching *:not(.theme-icon):not(.theme-veil)::before,
body.theme-switching *:not(.theme-icon):not(.theme-veil)::after {
  transition: none !important;
}

/*
 * Theme change veil.
 *
 * The switch used to be a hard-edged circle wiping across the viewport, which
 * read as abrupt no matter how it was eased. Instead the page now dips into the
 * incoming theme's own background colour and lifts back off it, so the whole
 * surface simply darkens (or lightens) into place. base_theme_switcher.js
 * drives the opacity and swaps the theme while this is opaque, so the repaint
 * itself is never visible.
 *
 * Colours are overridable per project; they default to the base light/dark page
 * backgrounds so the dip blends with the page rather than flashing pure
 * black/white.
 */
.theme-veil {
  position: fixed;
  inset: 0;
  z-index: 2147483000;
  pointer-events: none;
  opacity: 0;
  will-change: opacity;
  background: var(--theme-veil-light, #fffcfd);
}

.theme-veil[data-target='dark'] {
  background: var(--theme-veil-dark, #1d161c);
}

@media (prefers-reduced-motion: reduce) {
  /* JS applies the theme instantly in this mode; belt and braces in case a
     veil is ever inserted anyway. */
  .theme-veil {
    display: none;
  }
  .theme-icon {
    transition: none !important;
  }
}

/* ---------------------------------------------------------------------------
   Two-way theme control (light / dark) with a sliding knob.

   Markup: web/layout/navbar/theme_control.jinja2. Used by the navbar rail, the
   mobile drawer and the docs top bar. Moved here from base_navbar_panels.css so
   any page that loads the theme switcher gets the control styled, with no navbar
   dependency.
   --------------------------------------------------------------------------- */

.nb-theme {
  position: relative;
  display: inline-flex;
  align-self: center;
  border: 1px solid var(--border-color);
  background: var(--brand-softer);
  border-radius: 20px;
  padding: 2px;
  margin: 2px 8px 0;
}

.nb-theme__knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 32px;
  height: 26px;
  border-radius: 16px;
  background: var(--nb-knob);
  box-shadow: 0 2px 6px -2px var(--nb-shadow);
  z-index: 0;
  /* Index set by base_navbar.js from the active preference. */
  transform: translateX(calc(var(--nb-theme-index, 0) * 32px));
}

.nb-theme__btn {
  position: relative;
  z-index: 1;
  /* Fixed box: the knob is positioned by multiplying this width, so the two must
     agree or the knob drifts out from under the icons. */
  width: 32px;
  height: 26px;
  flex: 0 0 32px;
  border: none;
  background: none;
  border-radius: 16px;
  display: grid;
  place-items: center;
  padding: 0;
  margin: 0;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  color: var(--muted-text);
}

.nb-theme__btn.tooltip-wrapper {
  display: grid;
}

/*
 * Pin the glyphs.
 *
 * base_elements.css puts `transition: all .3s ease` on icons, so ANY incidental
 * change - the knob sliding underneath, a font swapping in, a reflow - gets
 * animated, which reads as the icons drifting around independently of the knob.
 * Declaring the transition explicitly (and only for colour) beats that by
 * specificity and leaves the knob as the single moving part.
 */
.nb-theme__btn i {
  display: block;
  width: 14px;
  height: 14px;
  line-height: 14px;
  text-align: center;
  font-size: 14px;
  transform: none;
  transition: color 0.2s ease;
}

.nb-theme__btn:hover i {
  transform: none;
}

/*
 * Hover feedback.
 *
 * The control had no hover styling at all: pointing at a mode changed nothing,
 * and against the brand-tinted knob the glyph could read as washed out or gone.
 * A faint pad plus lifting the glyph to the primary text colour makes the
 * target unmistakable in both themes.
 */
.nb-theme__btn:hover {
  background: color-mix(in srgb, var(--text-primary) 12%, transparent);
}

.nb-theme__btn:hover i {
  color: var(--text-primary);
}

.nb-theme__btn.is-active {
  color: var(--brand);
}

/*
 * The selected mode sits on the knob, which is itself mixed from the brand
 * colour - so painting its glyph --brand puts the same hue on itself and it
 * sinks into the background. In dark the knob is a muted maroon and the effect
 * is worst there, so anchor the glyph to the ink that sits on a brand fill; the
 * tinted knob still carries the "selected" signal. Light keeps --brand: that
 * knob is the plain surface colour, where the accent reads cleanly.
 *
 * --primary-ink rather than a literal white: it is #ffffff today, so this is not
 * a visual change, but a project with a pale brand overrides that token to get
 * readable ink on its fills and this glyph now follows.
 */
body.theme-dark .nb-theme__btn.is-active,
body.theme-dark .nb-theme__btn.is-active i {
  color: var(--primary-ink);
}
