Files
Dashboard/app/globals.css
T
dejanandClaude Opus 5 7bbbd00ed2 Fokusring nur noch bei Tastaturbedienung zeigen
Nach dem Oeffnen der Schublade lag ein blauer Rahmen um "Dashboard", nach dem
Schliessen um den Hamburger — bis man woanders hinklickte. Der Ring hat einen
praktischen Grund, aber nur fuer die Tastatur: Er zeigt, wo man gerade steht.
Nach einem Mausklick weiss man das ohnehin.

Ursache war unser eigener Fokus-Sprung, nicht die CSS-Regel. Die benutzt
laengst :focus-visible. Setzt aber ein Skript den Fokus — Fokusfalle beim
Oeffnen, Rueckgabe an den Ausloeser beim Schliessen —, wertet Chrome das wie
Tastaturbedienung und zeigt den Ring trotzdem.

Drei Aenderungen:

- Beim Oeffnen bekommt der Dialograhmen den Fokus statt des ersten Links. Das
  ist ohnehin das uebliche Vorgehen fuer einen Dialog; die Sprachausgabe liest
  den Dialog an, der erste Tabulatorschritt landet auf dem ersten Link.

- Elemente mit tabindex="-1" bekommen keinen Ring mehr. Sie sind aus der
  Tabulatorreihenfolge heraus und werden nur per Skript fokussiert — ein Ring
  um den ganzen Schubladenrahmen waere dort Laerm.

- AppShell schreibt die zuletzt benutzte Eingabeart als data-eingabe an das
  Wurzelelement. Solange sie "zeiger" ist, entfaellt der Ring an Knoepfen und
  Links. Eingabefelder sind ausgenommen, dort gehoert er zum Zustand "hier
  wird gerade geschrieben". Der erste Tastendruck schaltet ihn ueberall zurueck.

Dabei ist eine Luecke in der Fokusfalle aufgefallen und behoben: Mit dem Fokus
auf dem Rahmen lief Umschalt+Tab aus dem Dialog heraus, weil die Falle nur den
ersten Link als Umkehrpunkt kannte. Der Rahmen steht im Dokument vor seinen
Kindern und gehoert dazu — sonst waere die Zusage von aria-modal gebrochen.

Nachgemessen statt begutachtet, alle Faelle:
  Maus offen        → Rahmen, kein Ring
  Maus zu           → Hamburger, kein Ring
  Tastatur offen    → Rahmen, kein Ring
  Tastatur erstes   → "Dashboard", RING
  Tastatur rueckwaerts → "Komponenten", RING (Falle haelt)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
2026-08-31 19:48:26 +02:00

200 lines
6.8 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@import "tailwindcss";
@import "../ui/theme.css";
/*
* Schrift: Instrument Sans, selbst gehostet — identisch zur Software.
*
* Die Dateien stammen aus `apps/web/public/fonts/` von HiveGrid Cloud, damit
* Schriftschnitt und Metrik exakt übereinstimmen. Variable Schrift (400–700).
*
* Warum das nötig war: `ui/theme.css` verlangt für alle Subframe-Typo-Token
* bereits "Instrument Sans", die Schrift wurde aber nie geladen — und der
* Fließtext war zusätzlich auf Inter gesetzt. Ergebnis waren zwei verschiedene
* Schriften auf einer Seite, keine davon die der Software.
*/
@font-face {
font-family: "Instrument Sans";
font-style: normal;
font-weight: 400 700;
font-stretch: 100%;
font-display: swap;
src: url("/fonts/instrument-sans-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: "Instrument Sans";
font-style: normal;
font-weight: 400 700;
font-stretch: 100%;
font-display: swap;
src: url("/fonts/instrument-sans-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/*
* Einige Subframe-Komponenten verweisen noch direkt auf Inter. Damit sie nicht
* auf die Systemschrift zurückfallen, zeigt der Name auf dieselbe Datei —
* so hält es die Software auch.
*/
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400 700;
font-stretch: 100%;
font-display: swap;
src: url("/fonts/instrument-sans-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
@theme {
--default-font-family: "Instrument Sans", ui-sans-serif, system-ui,
-apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
--font-inter: var(--default-font-family);
--font-sans: var(--default-font-family);
}
/*
* HiveGrid Analytics Dashboard
* ---------------------------------------------------------------
* Chrome (Sidebar, Karten, Buttons, Tabellen) nutzt die Subframe-
* Design-Tokens aus ui/theme.css.
* Die Datenvisualisierung folgt IBM Carbon (siehe docs/DESIGN-SYSTEM.md)
* und definiert eigene Tokens, damit Charts unabhaengig vom Brand-Theme
* lesbar und barrierearm bleiben.
*/
:root {
/* --- Carbon Data-Viz Tokens (Light Theme) --- */
--dv-grid: #e0e0e0; /* cds-layer-accent-01 - Gridlines */
--dv-axis: #8d8d8d; /* cds-border-strong-01 - Achsenlinie */
--dv-text: #161616; /* cds-text-primary - Chart-Titel */
--dv-text-secondary: #525252;/* cds-text-secondary - Achsenlabels */
--dv-tooltip-bg: #393939; /* cds-background-inverse */
--dv-tooltip-fg: #ffffff; /* cds-text-inverse */
/* Vertikaler Rhythmus fuer Dashboard-Raster (8px-System) */
--dv-card-padding: 16px;
--dv-card-gap: 16px;
}
body {
background: var(--color-neutral-50, #fafafa);
color: var(--color-text-neutral-primary);
font-family: var(--default-font-family);
font-variant-numeric: tabular-nums;
}
/*
* Fokus-Sichtbarkeit.
* Eine Regel fuer alles Interaktive statt focus:-Klassen an jedem Element.
* :focus-visible zeigt den Ring nur bei Tastaturbedienung, nicht beim Klick.
*/
/*
* `[tabindex="-1"]` ist ausgenommen: Solche Elemente sind aus der
* Tabulatorreihenfolge heraus und bekommen den Fokus ausschliesslich per
* Skript — bei uns der Rahmen der Schublade, damit die Sprachausgabe den
* Dialog anliest. Ein Ring um den ganzen Rahmen waere dort keine Orientierung,
* sondern Laerm; die Orientierung gibt der naechste Tabulatorschritt.
*/
:where(
a,
button,
[role="button"],
input,
select,
textarea,
[tabindex]:not([tabindex="-1"])
):focus-visible {
outline: none;
box-shadow: var(--shadow-focus, 0 0 0 3px rgb(7 145 240 / 0.4));
border-radius: var(--radius-sm, 4px);
}
/*
* Nachtrag zu :focus-visible — ein Fall, den der Browser falsch einschaetzt.
*
* Setzt ein Skript den Fokus, behandelt Chrome das wie Tastaturbedienung. Beim
* Oeffnen und Schliessen der Schublade tun wir genau das (Fokusfalle rein,
* Fokus zurueck auf den Hamburger) — nach einem Mausklick stand der Ring
* danach sichtbar da, bis man woanders hinklickte.
*
* `data-eingabe` schreibt AppShell mit: "zeiger" oder "tastatur", je nach
* letzter Eingabe. Der Ring entfaellt nur waehrend Zeigerbedienung und nur an
* Knoepfen und Links. Eingabefelder sind ausgenommen — dort gehoert der Ring
* zum Zustand "hier wird gerade geschrieben", auch nach einem Klick. Der erste
* Tastendruck schaltet ihn ueberall wieder ein.
*/
:root[data-eingabe="zeiger"]
:where(a, button, [role="button"], [tabindex]:not([tabindex="-1"])):focus-visible {
box-shadow: none;
}
/*
* Der Einklapp-Knopf der Seitenleiste ragt bauartbedingt 17 px nach rechts
* heraus. Faehrt die Leiste unterhalb `md` als Schublade nach links aus dem
* Bild, bleibt genau dieser Ueberstand bei x = -16 sichtbar: ein angeschnittener
* Knopf, der anklickbar ist und nichts Sichtbares bewirkt, weil er nur den
* Zustand der unsichtbaren Schublade aendert.
*
* Einklappen ergibt in einer Schublade ohnehin keinen Sinn — dort oeffnet und
* schliesst der Hamburger in der Kopfzeile. Also unterhalb `md` ausblenden.
* `group/7ce7d712` ist der von Subframe erzeugte Marker des Knopf-Wrappers in
* SidebarWithSections; er aendert sich nur bei einem bewussten Resync.
*/
@media (max-width: 767px) {
[data-shell-sidebar] [class*="group/7ce7d712"] {
display: none;
}
}
/* Radix-Portale (Dropdowns, Tooltips) ueber den Sticky-Header heben. */
[data-radix-popper-content-wrapper] {
z-index: 1000 !important;
}
/* Recharts: Fokus-Outline der SVG-Wrapper unterdruecken, Cursor vereinheitlichen. */
.recharts-wrapper:focus,
.recharts-surface:focus {
outline: none;
}
.recharts-sector,
.recharts-rectangle,
.recharts-dot {
transition: opacity 140ms ease, filter 140ms ease;
}
/* Waagerecht scrollende Leisten ohne sichtbaren Balken: Der Balken wuerde
unter einem 40 px hohen Reiterband mehr stoeren als helfen; dass gescrollt
werden kann, zeigt der angeschnittene letzte Reiter. */
.dv-scroll-x {
scrollbar-width: none;
}
.dv-scroll-x::-webkit-scrollbar {
display: none;
}
/* Scrollbars in Karten dezent halten. */
.dv-scroll::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.dv-scroll::-webkit-scrollbar-thumb {
background: #d4d4d4;
border-radius: 999px;
}
.dv-scroll::-webkit-scrollbar-track {
background: transparent;
}
@media print {
.dv-no-print {
display: none !important;
}
}