Make the mobile theme control a toggle
The header was lifting Starlight's theme select out of the hamburger, so the
mobile control was still a menu: open it, read three options, pick one. It is
a button now, and one tap flips light and dark.
Auto stays out of the cycle and stays implicit. With nothing stored the site
follows the system preference and keeps following it live, and the first tap
is what turns an inferred theme into a stored choice. Anyone who wants to
hand the decision back to the system still has Starlight's own select, with
its explicit Auto option, in the mobile menu.
No theme state is forked. The button sets the value on Starlight's select and
fires its change event, so the site lands in exactly the state it would have
been in had the reader picked that option from the menu: updatePickers, the
data-theme attribute and the starlight-theme key are all written by
Starlight's own handler. The button then reads its state back from data-theme,
which is the output of that same path, so it cannot disagree with the desktop
control or with the before-paint script.
The icon is the mode the tap would give you, not the mode you are in, and the
accessible name says the same in words ("Switch to dark theme"), updated from
the same attribute. The desktop select keeps showing the current mode
instead; the two are never on screen together, so I left it alone.
Driven in headless Chrome from both system preferences: initial state follows
the system, a live system flip is followed while nothing is stored, Enter on
the focused button flips it, a tap flips it back, a reload keeps it, a system
flip after a choice is ignored, and clearing storage returns to following the
system. Both Starlight selects agree with the button after every step.
Make the mobile theme control a toggle
The header was lifting Starlight's theme select out of the hamburger, so the
mobile control was still a menu: open it, read three options, pick one. It is
a button now, and one tap flips light and dark.
Auto stays out of the cycle and stays implicit. With nothing stored the site
follows the system preference and keeps following it live, and the first tap
is what turns an inferred theme into a stored choice. Anyone who wants to
hand the decision back to the system still has Starlight's own select, with
its explicit Auto option, in the mobile menu.
No theme state is forked. The button sets the value on Starlight's select and
fires its change event, so the site lands in exactly the state it would have
been in had the reader picked that option from the menu: updatePickers, the
data-theme attribute and the starlight-theme key are all written by
Starlight's own handler. The button then reads its state back from data-theme,
which is the output of that same path, so it cannot disagree with the desktop
control or with the before-paint script.
The icon is the mode the tap would give you, not the mode you are in, and the
accessible name says the same in words ("Switch to dark theme"), updated from
the same attribute. The desktop select keeps showing the current mode
instead; the two are never on screen together, so I left it alone.
Driven in headless Chrome from both system preferences: initial state follows
the system, a live system flip is followed while nothing is stored, Enter on
the focused button flips it, a tap flips it back, a reload keeps it, a system
flip after a choice is ignored, and clearing storage returns to following the
system. Both Starlight selects agree with the button after every step.