feat(t5): Fokusring für alle, 44-px-Ziele bei Touch, 16-px-Schrift (T5a A5)

- globals.css: eine Basisregel :where(:focus-visible) mit --focus-width
  und --focus-offset (Sonne 3 px), Firefox-:-moz-focusring gleichgezogen;
  --text-xs 0.8125rem.
- Fokus-Codemod (scripts/codemod-t5-focus.mjs): eigene Ringe und
  outline-none raus, sm:h-/sm:size- zu pointer-fine:, Label-Zeilen mit
  focus-ring-within; Skript-Fokus (Lücken-Liste, „Gespeichert“) bleibt.
- Button/Input 44 px, kompakt nur mit Maus; Icon-Knöpfe mit unsichtbarer
  44-px-Trefferfläche bei Touch, Nachbarn mit genug Abstand.
- 16 px in Feldern, Labels, Auswahl, Leerzuständen, Listentiteln.
- .holo-stage auf allen Beute-Bühnen, .stage-card holt den Seitenring.
- Baukasten-Wächter (src/styles/baukasten-guard.spec.ts) mit den Regeln
  aus A3–A5, Ausnahmen mit Grund; Kalender-Auswahl als Inset-Ring.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick.RosenloecherandClaude Opus 5.5 committed 2026-10-16 18:06:20 +02:00
1 parent 62ab080725
commit ce68729233
85 files changed
+935 -139

No files matched your search

@@ -174,6 +174,24 @@ describe("HiveCard", () => {
expect(screen.getByText("1 Änderung wartet auf Netz")).toBeInTheDocument();
});
it("the stage is a .holo-stage and the outline panel on it takes the page focus ring back", async () => {
renderCard();
const toggle = await screen.findByRole("button", { name: "Aufbau als Liste" });
expect(screen.getByRole("img", { name: /Beute mit/ }).closest(".holo-stage")).not.toBeNull();
expect(toggle.closest(".holo-stage")).not.toBeNull();
await userEvent.click(toggle);
const panel = document.getElementById(toggle.getAttribute("aria-controls")!)!;
expect(panel).toHaveClass("stage-card");
});
it("the loading stage is a .holo-stage too", () => {
vi.mocked(fetchHive).mockReturnValue(new Promise(() => {}));
renderCard();
expect(screen.getByRole("status", { name: "Beute wird geladen" })).toHaveClass("holo-stage");
});
it("keeps the outline in the DOM but visually hidden until „Aufbau als Liste“", async () => {
renderCard();
const toggle = await screen.findByRole("button", { name: "Aufbau als Liste" });