/* Day/night switch — ONE definition, shared by the portal shell and the admin SPA.
   Consumed two ways:
     • /index.html → <link rel="stylesheet" href="/theme-toggle.css">
     • /admin/     → build-time @import from admin-src/src/index.css, which
                     inlines it into the hashed admin CSS (no extra request).

   It lives in its own file rather than in styles.css because the admin cannot
   take styles.css — that is 800 lines of portal layout. The alternative was a
   Tailwind reimplementation inside admin-src/src/theme.tsx, and this repo has
   already paid for that: the admin shipped a three-position System/Light/Dark
   segmented control long after the portal replaced its own with this switch, so
   the two surfaces of one origin disagreed about what a theme control even is.
   Duplicate-with-a-comment was also tried for the logged-out palette and
   drifted until not one value matched. Hence: one file, both surfaces.

   Depends only on the --mua-* tokens, so it needs tokens.css and nothing else.

   MARKUP CONTRACT — copy it verbatim; the CSS assumes this nesting:

     <button class="theme-toggle" type="button" role="switch" aria-checked="false">
       <span class="vh">Dark mode</span>              <!-- see note below -->
       <span class="theme-toggle-track" aria-hidden="true">
         <svg class="theme-toggle-icon theme-toggle-sun" …/>
         <svg class="theme-toggle-icon theme-toggle-moon" …/>
         <span class="theme-toggle-thumb"></span>
       </span>
     </button>

   role="switch" is the right pattern for two states: the accessible name stays
   constant and aria-checked carries the state, so a screen reader says "Dark
   mode, switch, on" rather than renaming itself on every press.

   The name span needs each surface's own visually-hidden utility — `vh` in the
   portal, `sr-only` in the admin — because that utility is not this file's to
   own. It must NOT be display:none: the icons are aria-hidden, so dropping the
   span from the accessibility tree leaves the switch with no name at all. */

.theme-toggle {
  display: inline-flex;
  align-items: center;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  color: inherit;
  -webkit-tap-highlight-color: transparent;
}

/* box-sizing is stated rather than inherited from the host reset. Both surfaces
   happen to set border-box globally today (styles.css:32, Tailwind preflight),
   but the geometry below only works in border-box and a switch that silently
   grows 16px on the next surface is exactly the drift this file exists to stop.

   The numbers are one system: 52 total - 2 border = a 50px padding box, and the
   thumb (2px insets, 22px wide, +24px travel) lands 2px from each end. Change
   one and re-derive the rest. */
.theme-toggle-track {
  box-sizing: border-box;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  inline-size: 52px;
  block-size: 28px;
  padding: 0 7px;
  border: 1px solid var(--mua-border);
  border-radius: 999px;
  background: var(--mua-surface-sunken);
}

/* Both icons are always painted, at opposite ends. The thumb slides over the
   one that is NOT active, so the visible icon is the theme you are in — not
   the one you would switch to. Showing the destination instead is the coin-flip
   every icon-only theme button gets wrong; a track with a thumb has room to be
   unambiguous, so it should be. */
.theme-toggle-icon {
  position: relative;
  z-index: 1;
  inline-size: 14px;
  block-size: 14px;
  flex: none;
  color: var(--mua-text-muted);
  transition: color 160ms ease;
}

.theme-toggle-thumb {
  box-sizing: border-box;
  position: absolute;
  z-index: 0;
  inset-block-start: 2px;
  inset-inline-start: 2px;
  inline-size: 22px;
  block-size: 22px;
  border-radius: 50%;
  background: var(--mua-surface-raised);
  box-shadow: var(--mua-shadow-sm);
  transition: transform 200ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Driven from html[data-theme] — the RESOLVED theme theme.js writes before
   first paint — not from aria-checked, which the page's script only fixes up
   after it loads. Keying off the ARIA attribute would paint the thumb on the
   wrong side and then visibly slide across on load; in the admin, which mounts
   after React hydrates, that slide would be long enough to read.

   This is also why neither surface renders the switch from its own state: the
   look comes from the attribute, and the script only has to keep aria-checked
   honest.

   data-theme, not data-theme-pref: a two-state switch has nothing sensible to
   show for pref "system", and what the user wants to see is which theme they
   are actually looking at. */
html[data-theme="dark"] .theme-toggle-thumb { transform: translateX(24px); }
html[data-theme="light"] .theme-toggle-sun,
html[data-theme="dark"] .theme-toggle-moon { color: var(--mua-text); }

@media (hover: hover) and (pointer: fine) {
  .theme-toggle:hover .theme-toggle-track { border-color: var(--mua-text-muted); }
}

/* On the BUTTON, not the track, even though the visible control is the track.
   The button is a zero-padding wrapper whose border box measures identically to
   the track's (verified 52x28 at the same origin on both surfaces), so the ring
   lands in exactly the same place either way — but only the button-side rule
   replaces the UA ring. Chrome paints `outline: auto` on a focused <button>, and
   an author outline on a CHILD does not override it, so the previous track-side
   rule stacked our 2px ring outside Chrome's ring: two rings, and the inner one
   an off-palette orange. Every other focus ring in styles.css sits on the
   focusable element itself for the same reason. */
.theme-toggle:focus-visible {
  outline: 2px solid var(--mua-focus);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .theme-toggle-thumb { transition: none; }
  .theme-toggle-icon { transition: none; }
}
