/* The theme mechanism, and the control that drives it.
 *
 * Linked by every page unfussed.me and every door host serves, because both
 * halves have to exist everywhere: the two rules that turn a stored choice into
 * a rendered theme, and the switch that stores it.
 *
 * --- how a choice becomes a theme -----------------------------------------
 *
 * Every themed colour on this site is written once, as light-dark(light, dark),
 * in the stylesheet that owns it. light-dark() resolves against the root's USED
 * COLOUR SCHEME, so switching themes is a matter of narrowing that scheme —
 * which is what these two rules do, and they are the only two rules in the
 * codebase that a theme choice touches.
 *
 * With no choice made, :root keeps the `color-scheme: light dark` its own
 * stylesheet declares and the page follows the operating system, live, with no
 * JavaScript and no reload. A stored choice narrows it to one scheme, and
 * light-dark() follows — so an explicit light choice wins on a machine set to
 * dark, and an explicit dark choice wins on a machine set to light.
 *
 * `prefers-color-scheme` cannot express this and is deliberately not used
 * anywhere on the site any more. It reports the operating system's setting and
 * is NOT re-pointed by `color-scheme` — measured in the engine rather than
 * assumed, because assuming the opposite is very natural. A dark media query
 * would therefore go on firing underneath an explicit light choice, and undoing
 * that would mean a :not([data-theme="light"]) guard on every dark selector
 * plus a second copy of every dark declaration for the explicit case.
 *
 * `only` rather than a bare `light`/`dark` so the UA also stops applying any
 * automatic darkening of its own on top of a choice the reader has made.
 *
 * These same two rules are repeated in every stylesheet that declares
 * light-dark() pairs — /unfussed-job.css, /doors/doors.css and the inline
 * blocks on /account, /terms and /privacy. That is deliberate rather than
 * untidy: they are two identical declarations, and a sheet that carries its own
 * pairs should honour a stored choice even on a load where this file did not
 * arrive. The pairs and the rule that resolves them stay together.
 *
 * data-theme is stamped by the inline script in each page's head, BEFORE any
 * stylesheet, so the first paint is already the chosen theme. A preference read
 * after first paint gives a flash of the other theme on every single load, and
 * between warm paper and near-black that flash is violent.
 */
:root[data-theme="light"] { color-scheme: only light; }
:root[data-theme="dark"] { color-scheme: only dark; }
html, body { overflow-x: clip; }

/* --- the control ----------------------------------------------------------
 *
 * Three real radios in a fieldset rather than one button that cycles.
 *
 * A cycling button has to fold three states into one control, and its
 * accessible name can then say either where you are or what pressing it does —
 * never both. Whichever is chosen, the other is invisible: either you cannot
 * tell the current theme without changing it, or you cannot tell what the
 * button will do. Getting from light to dark can also take two presses with no
 * way to see that in advance.
 *
 * A radio group shows all three at once, and every one of its semantics is
 * native rather than reconstructed with ARIA: arrow keys move between options,
 * the group is one tab stop, and a screen reader announces "Colour theme,
 * Dark, radio button, 2 of 3, selected" without a live region or an
 * aria-label that has to be kept in step with the state.
 *
 * Each option carries a real text name — the glyph alone would leave the
 * control unlabelled — and on narrow screens that name is the accessible name
 * only, because three words will not fit beside two pills on a 390px screen.
 *
 * Every colour below reaches for a token with a light-dark() fallback, because
 * this file is also linked by /terms and /privacy, which define no tokens at
 * all and would otherwise render the control in one theme on both.
 */
.theme-switch {
  display: inline-flex;
  flex: none;
  gap: 2px;
  margin: 0;
  padding: 2px;
  border: 1px solid var(--line, light-dark(#d8d5c9, rgba(243, 240, 230, .16)));
  border-radius: 999px;
  /* A fieldset is min-width: min-content by default, which refuses to shrink
     and pushes the nav wider than the shell on a narrow screen. */
  min-width: 0;
}

.theme-switch legend {
  /* The group's name. Present for a screen reader, absent on screen: beside a
     wordmark and two pills there is no room for a fourth label, and the three
     glyphs read as a set without one. */
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The radio itself is the state and the keyboard target; the label is the
   visible control. Hidden this way rather than with display:none or
   visibility:hidden, both of which would take it out of the tab order and off
   the accessibility tree along with it. */
.theme-switch input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.theme-switch label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  /* 30px clears the 24px WCAG 2.2 minimum target with room to spare, and keeps
     the whole control shorter than the 44px pills it sits beside. */
  min-width: 32px;
  min-height: 30px;
  border-radius: 999px;
  color: var(--muted, light-dark(#667064, #a6b0a3));
  font-size: 13px;
  font-weight: 800;
  letter-spacing: -.01em;
  white-space: nowrap;
  cursor: pointer;
  transition: background .18s ease, color .18s ease;
}
.theme-switch label:hover { color: var(--text, currentColor); }

.theme-switch .theme-glyph {
  display: block;
  flex: none;
  width: 16px;
  height: 16px;
}

/* Each option's name — read out, never drawn.
   It was drawn at first, and three words cost about 200px: enough that a job
   page's nav ("All jobs", "What you get", "Questions", the account pill and the
   buy pill) wrapped onto two lines at 1440px, and enough to push the buy pill
   off the right edge of a 390px screen. The homepage, whose nav is shorter, had
   room — but a control that is worded on one page type and not on another is
   worse than one that is consistent, so the words come off everywhere.
   They remain the accessible name of each option, which is the part that
   carries the meaning for anyone who cannot see a crescent. */
.theme-word {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Even at 104px the switch is one control too many for a 390px topbar, where a
   wordmark and two pills already spend every pixel. The nav is allowed to wrap
   rather than let the buy pill be clipped by the edge of the screen — a pill
   that is half a pill is worse than a topbar that is two rows tall. */
@media (max-width: 640px) {
  .topbar { flex-wrap: wrap; row-gap: 10px; padding-bottom: 10px; }
  .topbar .nav, .topbar nav { flex-wrap: wrap; }
}

/* The chosen segment.
 *
 * Selected from the root stamp rather than from :checked, and that is not a
 * stylistic choice: the stamp is applied in the head before first paint, where
 * the radio's checked state cannot be — the control does not exist yet when
 * that script runs. Keying the appearance off :checked would paint the wrong
 * segment as chosen on every load until /theme.js caught up. /theme.js does set
 * checked, for the accessibility tree; this rule is what the eye sees.
 *
 * The last selector is the no-JavaScript case: nothing stamped, nothing stored,
 * the page follows the system — which is exactly what "System" means, so it is
 * shown as chosen and it is telling the truth. */
:root[data-theme-pref="light"] .theme-switch label[for="theme-light"],
:root[data-theme-pref="dark"] .theme-switch label[for="theme-dark"],
:root[data-theme-pref="system"] .theme-switch label[for="theme-system"],
:root:not([data-theme-pref]) .theme-switch label[for="theme-system"] {
  background: var(--acid, var(--lime, #d9ff57));
  /* Ink on lime in both themes — the fill does not flip, so nor may the type.
     See DESIGN.md, "Use Ink on Lucky lime, never white." */
  color: #162019;
}

/* The ring goes on the label, because the input it belongs to is a 1px box
   parked off to one side. The sitewide :focus-visible rule supplies the colour
   and width; only the shape is set here. */
.theme-switch input:focus-visible + label {
  outline: 3px solid var(--text, currentColor);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .theme-switch label { transition: none; }
}

/* /account, /terms and /privacy carry no topbar — their only chrome is a "back
   to all jobs" link at the head of <main>. This puts the switch on that line
   rather than inventing a header for three pages, so the control still sits
   beside the way back on every page type. */
.page-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
