The theme switcher used to render as a round 44×44 icon button while
the locale switcher next to it (in the footer's device-prefs cluster
since #162) renders as a small chip: icon + label + chevron. Two
controls sitting side-by-side with two different visual shapes read
as two unrelated widgets instead of one family of preferences.
This PR aligns the theme trigger on the locale chip shape:
Before: [☀] (round icon button, 44×44)
After: [☀ System ▾] (chip — icon + label + chevron)
The leading icon stays driven by `currentIcon()` so it still flips
between sun / moon / monitor as the user selects light / dark /
system — that visual feedback was the one reason the original icon-
only design existed and it's preserved.
Implementation:
* `theme-switcher.html` swaps the Tailwind utility-class icon button
for a `.theme-switcher__trigger` chip with three children — the
current-mode icon (size 14), the localised mode label, and a
`chevron-down` (size 12). Same children layout as
`.locale-switcher__trigger`.
* `theme-switcher.scss` adds `.theme-switcher__trigger` mirroring
`.locale-switcher__trigger` rule-for-rule: same chip metrics
(min-height 2.75rem for the AAA 44×44 tap target via vertical-
padding overflow inside the thin footer), same hover/focus tokens,
same dark-mode swap. Two copies rather than a shared `_chip-
trigger.scss` partial — two switchers in one app is below the
"three similar things" threshold from CLAUDE.md where extraction
starts paying off. Promotes when a third switcher lands.
No spec changes: the existing assertions check
`button[aria-haspopup="menu"]` + the aria-label content, both of
which are preserved. `triggerAriaLabel()` is unchanged.
Verification:
* 43 portal-shell specs pass.
* `pnpm nx run portal-shell:build:production` (i18n-strict) green
— confirms the `theme.mode.{light,dark,system}` labels are
already translated (they were used in the menu items before;
the trigger just reuses the same `currentLabel()` computed).