|
|
|
|
@ -1,168 +1,189 @@
|
|
|
|
|
/*
|
|
|
|
|
* Design-System der Syncova-Oberflaeche (Tailwind v4 + shadcn/ui).
|
|
|
|
|
* Design-System der Syncova-Oberfläche.
|
|
|
|
|
*
|
|
|
|
|
* Der Grundsatz aus PROMPT.md §106 gilt unveraendert und ist der Grund fuer den
|
|
|
|
|
* Zuschnitt dieser Datei: Semantische Farben ausschliesslich fuer Status. Die
|
|
|
|
|
* gesamte Oberflaeche ist neutral gehalten; wo Farbe erscheint, bedeutet sie
|
|
|
|
|
* etwas. Eine bunte Oberflaeche verschleiert, welche Information wirklich
|
|
|
|
|
* dringend ist — und in einer Backup-Konsole ist genau das die einzige Frage,
|
|
|
|
|
* die zaehlt.
|
|
|
|
|
* Die Farben, Radien, Schatten und die Schrift stammen aus dem Preset
|
|
|
|
|
* `b5vnF8SMi` (tweakcn). Es ist bewusst kantig (Radius 0), schattenlos und
|
|
|
|
|
* durchgehend in einer dicktengleichen Schrift — ein technischer, ruhiger Look.
|
|
|
|
|
*
|
|
|
|
|
* Deshalb gibt es hier keine "Markenfarbe" als Flaeche. Der Akzent ist ein
|
|
|
|
|
* gedecktes Blau und wird nur fuer Bedienelemente verwendet, nie fuer Zustaende.
|
|
|
|
|
* Drei Stellen weichen ab, und zwar begründet:
|
|
|
|
|
*
|
|
|
|
|
* 1. **Die Statusfarben bleiben.** Das Preset kennt nur `destructive` und fünf
|
|
|
|
|
* Diagrammfarben, aber PROMPT §106 verlangt fünf Bedeutungen: Grün, Gelb,
|
|
|
|
|
* Orange, Rot, Blau. Ohne sie ließe sich ein Teilfehler nicht von einem
|
|
|
|
|
* Erfolg unterscheiden — die eine Aussage, auf die es in dieser Konsole
|
|
|
|
|
* ankommt. Sie sind an die Neutraltöne des Presets angepasst.
|
|
|
|
|
* 2. **Das dunkle Thema hängt an `[data-theme='dark']`, nicht an `.dark`.** Der
|
|
|
|
|
* Umschalter der Konsole setzt dieses Attribut, und er ist getestet. Beide
|
|
|
|
|
* Schreibweisen werden unterstützt.
|
|
|
|
|
* 3. **Die Schrift lädt nicht nach.** Geist Mono steht zuerst im Stapel und
|
|
|
|
|
* wird verwendet, wenn sie auf dem Gerät liegt; sonst greift die
|
|
|
|
|
* System-Monospace. Eine Schrift von einem fremden Host zu holen verbietet
|
|
|
|
|
* die Content-Security-Policy der Auslieferung — und ein Backup-Server, der
|
|
|
|
|
* für seine Oberfläche ins Internet greift, wäre auch ohne CSP falsch.
|
|
|
|
|
*
|
|
|
|
|
* Die Benennung ist bewusst semantisch (`--surface-card`, `--text-primary`)
|
|
|
|
|
* statt shadcn-typisch (`--card`, `--foreground`): Die Zuordnung des Presets
|
|
|
|
|
* steht damit an genau einer Stelle, und ein Wechsel des Presets fasst keine
|
|
|
|
|
* einzige Komponente an.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
@import 'tailwindcss';
|
|
|
|
|
|
|
|
|
|
/* Dark Mode wird ueber ein Attribut geschaltet, nicht ueber die Medienabfrage
|
|
|
|
|
* allein: Der Betreiber soll die Wahl haben, und eine Konsole, die nachts von
|
|
|
|
|
* selbst umschaltet, waehrend jemand an einer Stoerung arbeitet, ist laestig. */
|
|
|
|
|
@custom-variant dark (&:where([data-theme='dark'], [data-theme='dark'] *));
|
|
|
|
|
/* Beide Schreibweisen: Der Umschalter setzt `data-theme`, `.dark` ist die
|
|
|
|
|
* shadcn-übliche Form und kostet nichts. */
|
|
|
|
|
@custom-variant dark (&:where([data-theme='dark'], [data-theme='dark'] *, .dark, .dark *));
|
|
|
|
|
|
|
|
|
|
@theme {
|
|
|
|
|
/* --- Schrift --- */
|
|
|
|
|
--font-sans:
|
|
|
|
|
system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
|
|
|
|
|
--font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
|
|
|
|
|
/* Geist Mono für alles — die Wahl des Presets. In einer Konsole voller
|
|
|
|
|
* Zahlen, Pfade und Kennungen ist das kein Stilbruch, sondern hilfreich:
|
|
|
|
|
* Ziffern stehen untereinander, und ein Pfad bricht dort, wo er soll. */
|
|
|
|
|
--font-sans: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
|
|
|
|
|
--font-mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
|
|
|
|
|
|
|
|
|
|
/* --- Radien --- */
|
|
|
|
|
--radius-sm: 0.375rem;
|
|
|
|
|
--radius-md: 0.5rem;
|
|
|
|
|
--radius-lg: 0.75rem;
|
|
|
|
|
--radius-xl: 1rem;
|
|
|
|
|
/* Radius 0 — das prägendste Merkmal des Presets. */
|
|
|
|
|
--radius-sm: 0;
|
|
|
|
|
--radius-md: 0;
|
|
|
|
|
--radius-lg: 0;
|
|
|
|
|
--radius-xl: 0;
|
|
|
|
|
--radius-2xl: 0;
|
|
|
|
|
|
|
|
|
|
/* Schatten statt Rahmen, wo Tiefe gemeint ist. Ein Rahmen trennt, ein
|
|
|
|
|
* Schatten hebt — Karten sollen heben, Tabellenzeilen trennen. */
|
|
|
|
|
--shadow-card: 0 1px 2px 0 hsl(240 20% 12% / 0.04), 0 1px 3px 0 hsl(240 20% 12% / 0.06);
|
|
|
|
|
--shadow-raised: 0 4px 12px -2px hsl(240 20% 12% / 0.10), 0 2px 4px -2px hsl(240 20% 12% / 0.06);
|
|
|
|
|
/* Das Preset ist schattenlos. Tiefe entsteht über Flächenkontrast. */
|
|
|
|
|
--shadow-card: none;
|
|
|
|
|
--shadow-raised: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Die Farben liegen als CSS-Variablen vor, damit dieselbe Komponente in beiden
|
|
|
|
|
* Themen funktioniert, ohne dass jede Klasse eine dark:-Variante braucht.
|
|
|
|
|
*/
|
|
|
|
|
:root,
|
|
|
|
|
[data-theme='light'] {
|
|
|
|
|
/* Flaechen — vier Ebenen reichen: Seite, Karte, erhoben, Rand. */
|
|
|
|
|
--surface-page: 240 20% 97%;
|
|
|
|
|
--surface-card: 0 0% 100%;
|
|
|
|
|
--surface-raised: 0 0% 100%;
|
|
|
|
|
--surface-sunken: 240 20% 96%;
|
|
|
|
|
--surface-hover: 240 20% 94%;
|
|
|
|
|
[data-theme='light'],
|
|
|
|
|
.light {
|
|
|
|
|
/* --- Flächen --- */
|
|
|
|
|
--surface-page: oklch(1 0 0);
|
|
|
|
|
--surface-card: oklch(1 0 0);
|
|
|
|
|
--surface-raised: oklch(1 0 0);
|
|
|
|
|
--surface-sunken: oklch(0.9702 0 0);
|
|
|
|
|
--surface-hover: oklch(0.9702 0 0);
|
|
|
|
|
/* Die Seitenleiste hat im Preset eine eigene, leicht abgesetzte Fläche. */
|
|
|
|
|
--surface-sidebar: oklch(0.9851 0 0);
|
|
|
|
|
|
|
|
|
|
--border-default: 240 12% 90%;
|
|
|
|
|
--border-strong: 240 10% 80%;
|
|
|
|
|
--border-default: oklch(0.9219 0 0);
|
|
|
|
|
--border-strong: oklch(0.709 0 0);
|
|
|
|
|
|
|
|
|
|
--text-primary: 240 20% 12%;
|
|
|
|
|
--text-secondary: 240 8% 44%;
|
|
|
|
|
--text-muted: 240 6% 58%;
|
|
|
|
|
--text-inverted: 0 0% 100%;
|
|
|
|
|
--text-primary: oklch(0.1448 0 0);
|
|
|
|
|
--text-secondary: oklch(0.5555 0 0);
|
|
|
|
|
--text-muted: oklch(0.709 0 0);
|
|
|
|
|
--text-inverted: oklch(0.9691 0.0161 293.7558);
|
|
|
|
|
|
|
|
|
|
/* Akzent — Bedienelemente, niemals Zustand. */
|
|
|
|
|
--accent: 243 75% 58%;
|
|
|
|
|
--accent-hover: 243 75% 50%;
|
|
|
|
|
--accent-text: 0 0% 100%;
|
|
|
|
|
--accent-subtle: 243 75% 96%;
|
|
|
|
|
/* Akzent = `primary` des Presets, nicht dessen `accent`.
|
|
|
|
|
*
|
|
|
|
|
* In shadcn ist `accent` die dezente Hover-Fläche und `primary` die Farbe der
|
|
|
|
|
* Handlung. Die beiden zu verwechseln machte jede Schaltfläche grau. */
|
|
|
|
|
--accent: oklch(0.4907 0.2699 292.5633);
|
|
|
|
|
--accent-hover: oklch(0.4316 0.232 292.7118);
|
|
|
|
|
--accent-text: oklch(0.9691 0.0161 293.7558);
|
|
|
|
|
--accent-subtle: oklch(0.9674 0.0013 286.3752);
|
|
|
|
|
|
|
|
|
|
/* --- Statusfarben (PROMPT.md §106) ---
|
|
|
|
|
* Gruen = Healthy, Gelb = Warning, Orange = High, Rot = Critical,
|
|
|
|
|
* Blau/Neutral = Information. Sonst nichts. */
|
|
|
|
|
--status-healthy: 142 72% 29%;
|
|
|
|
|
--status-healthy-bg: 142 60% 95%;
|
|
|
|
|
--status-warning: 38 92% 33%;
|
|
|
|
|
--status-warning-bg: 45 90% 94%;
|
|
|
|
|
--status-high: 21 90% 40%;
|
|
|
|
|
--status-high-bg: 24 90% 95%;
|
|
|
|
|
--status-critical: 0 74% 42%;
|
|
|
|
|
--status-critical-bg: 0 85% 96%;
|
|
|
|
|
--status-info: 221 83% 45%;
|
|
|
|
|
--status-info-bg: 214 95% 96%;
|
|
|
|
|
--status-neutral: 240 4% 42%;
|
|
|
|
|
--status-neutral-bg: 240 5% 95%;
|
|
|
|
|
/* --- Statusfarben (PROMPT §106) ---
|
|
|
|
|
* Grün = Healthy, Gelb = Warning, Orange = High, Rot = Critical,
|
|
|
|
|
* Blau/Neutral = Information. Rot stammt aus `destructive` des Presets. */
|
|
|
|
|
--status-healthy: oklch(0.52 0.14 152);
|
|
|
|
|
--status-healthy-bg: oklch(0.96 0.03 152);
|
|
|
|
|
--status-warning: oklch(0.55 0.12 85);
|
|
|
|
|
--status-warning-bg: oklch(0.96 0.04 85);
|
|
|
|
|
--status-high: oklch(0.56 0.17 45);
|
|
|
|
|
--status-high-bg: oklch(0.96 0.04 45);
|
|
|
|
|
--status-critical: oklch(0.583 0.2387 28.4765);
|
|
|
|
|
--status-critical-bg: oklch(0.96 0.03 28);
|
|
|
|
|
--status-info: oklch(0.5405 0.2811 292.8523);
|
|
|
|
|
--status-info-bg: oklch(0.96 0.02 293);
|
|
|
|
|
--status-neutral: oklch(0.5555 0 0);
|
|
|
|
|
--status-neutral-bg: oklch(0.9702 0 0);
|
|
|
|
|
|
|
|
|
|
--focus-ring: 221 83% 53%;
|
|
|
|
|
--focus-ring: oklch(0.4907 0.2699 292.5633);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-theme='dark'] {
|
|
|
|
|
--surface-page: 240 15% 7%;
|
|
|
|
|
--surface-card: 240 13% 10%;
|
|
|
|
|
--surface-raised: 240 12% 13%;
|
|
|
|
|
--surface-sunken: 240 16% 5%;
|
|
|
|
|
--surface-hover: 240 12% 16%;
|
|
|
|
|
[data-theme='dark'],
|
|
|
|
|
.dark {
|
|
|
|
|
--surface-page: oklch(0.1448 0 0);
|
|
|
|
|
--surface-card: oklch(0.2046 0 0);
|
|
|
|
|
--surface-raised: oklch(0.2046 0 0);
|
|
|
|
|
--surface-sunken: oklch(0.2686 0 0);
|
|
|
|
|
--surface-hover: oklch(0.2686 0 0);
|
|
|
|
|
--surface-sidebar: oklch(0.2046 0 0);
|
|
|
|
|
|
|
|
|
|
--border-default: 240 8% 20%;
|
|
|
|
|
--border-strong: 240 8% 30%;
|
|
|
|
|
/* Das Preset setzt im dunklen Thema reines Schwarz als Rand: Flächen trennen
|
|
|
|
|
* sich über ihre Helligkeit, nicht über Linien. Übernommen. */
|
|
|
|
|
--border-default: oklch(0 0 0);
|
|
|
|
|
--border-strong: oklch(0.3 0 0);
|
|
|
|
|
|
|
|
|
|
--text-primary: 240 20% 97%;
|
|
|
|
|
--text-secondary: 240 8% 70%;
|
|
|
|
|
--text-muted: 240 6% 54%;
|
|
|
|
|
--text-inverted: 240 15% 7%;
|
|
|
|
|
--text-primary: oklch(0.9851 0 0);
|
|
|
|
|
--text-secondary: oklch(0.709 0 0);
|
|
|
|
|
--text-muted: oklch(0.5555 0 0);
|
|
|
|
|
--text-inverted: oklch(0.9691 0.0161 293.7558);
|
|
|
|
|
|
|
|
|
|
--accent: 243 80% 70%;
|
|
|
|
|
--accent-hover: 243 80% 78%;
|
|
|
|
|
--accent-text: 240 15% 7%;
|
|
|
|
|
--accent-subtle: 243 45% 20%;
|
|
|
|
|
--accent: oklch(0.6006 0.2425 293.8885);
|
|
|
|
|
--accent-hover: oklch(0.8101 0.1055 293.6966);
|
|
|
|
|
--accent-text: oklch(0.1448 0 0);
|
|
|
|
|
--accent-subtle: oklch(0.2739 0.0055 286.0326);
|
|
|
|
|
|
|
|
|
|
/* Im dunklen Thema werden die Statusfarben aufgehellt. Die dunklen Toene des
|
|
|
|
|
* hellen Themas waeren auf dunklem Grund nicht mehr unterscheidbar — und ein
|
|
|
|
|
* nicht unterscheidbarer Statuston ist schlimmer als gar keiner. */
|
|
|
|
|
--status-healthy: 142 65% 55%;
|
|
|
|
|
--status-healthy-bg: 142 45% 15%;
|
|
|
|
|
--status-warning: 45 90% 60%;
|
|
|
|
|
--status-warning-bg: 40 50% 15%;
|
|
|
|
|
--status-high: 25 92% 60%;
|
|
|
|
|
--status-high-bg: 22 55% 15%;
|
|
|
|
|
--status-critical: 0 85% 65%;
|
|
|
|
|
--status-critical-bg: 0 50% 16%;
|
|
|
|
|
--status-info: 217 90% 65%;
|
|
|
|
|
--status-info-bg: 220 50% 17%;
|
|
|
|
|
--status-neutral: 240 5% 65%;
|
|
|
|
|
--status-neutral-bg: 240 5% 18%;
|
|
|
|
|
/* Aufgehellt, sonst wären die Töne auf dunklem Grund nicht unterscheidbar —
|
|
|
|
|
* und ein nicht unterscheidbarer Statuston ist schlimmer als gar keiner. */
|
|
|
|
|
--status-healthy: oklch(0.75 0.16 152);
|
|
|
|
|
--status-healthy-bg: oklch(0.28 0.05 152);
|
|
|
|
|
--status-warning: oklch(0.82 0.15 85);
|
|
|
|
|
--status-warning-bg: oklch(0.29 0.05 85);
|
|
|
|
|
--status-high: oklch(0.75 0.16 45);
|
|
|
|
|
--status-high-bg: oklch(0.29 0.06 45);
|
|
|
|
|
--status-critical: oklch(0.7022 0.1892 22.2279);
|
|
|
|
|
--status-critical-bg: oklch(0.29 0.07 22);
|
|
|
|
|
--status-info: oklch(0.8101 0.1055 293.6966);
|
|
|
|
|
--status-info-bg: oklch(0.29 0.06 293);
|
|
|
|
|
--status-neutral: oklch(0.709 0 0);
|
|
|
|
|
--status-neutral-bg: oklch(0.2686 0 0);
|
|
|
|
|
|
|
|
|
|
--focus-ring: 217 90% 62%;
|
|
|
|
|
--focus-ring: oklch(0.6006 0.2425 293.8885);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Die Variablen werden Tailwind als Farben bekannt gemacht, damit
|
|
|
|
|
* bg-surface-card, text-status-critical usw. unmittelbar funktionieren. */
|
|
|
|
|
/* Die Variablen werden Tailwind als Farben bekannt gemacht, damit `bg-card`,
|
|
|
|
|
* `text-fg` und `text-critical` unmittelbar funktionieren. */
|
|
|
|
|
@theme inline {
|
|
|
|
|
--color-page: hsl(var(--surface-page));
|
|
|
|
|
--color-card: hsl(var(--surface-card));
|
|
|
|
|
--color-raised: hsl(var(--surface-raised));
|
|
|
|
|
--color-sunken: hsl(var(--surface-sunken));
|
|
|
|
|
--color-hover: hsl(var(--surface-hover));
|
|
|
|
|
--color-page: var(--surface-page);
|
|
|
|
|
--color-card: var(--surface-card);
|
|
|
|
|
--color-raised: var(--surface-raised);
|
|
|
|
|
--color-sunken: var(--surface-sunken);
|
|
|
|
|
--color-hover: var(--surface-hover);
|
|
|
|
|
--color-sidebar: var(--surface-sidebar);
|
|
|
|
|
|
|
|
|
|
--color-line: hsl(var(--border-default));
|
|
|
|
|
--color-line-strong: hsl(var(--border-strong));
|
|
|
|
|
--color-line: var(--border-default);
|
|
|
|
|
--color-line-strong: var(--border-strong);
|
|
|
|
|
|
|
|
|
|
--color-fg: hsl(var(--text-primary));
|
|
|
|
|
--color-fg-muted: hsl(var(--text-secondary));
|
|
|
|
|
--color-fg-subtle: hsl(var(--text-muted));
|
|
|
|
|
--color-fg-inverted: hsl(var(--text-inverted));
|
|
|
|
|
--color-fg: var(--text-primary);
|
|
|
|
|
--color-fg-muted: var(--text-secondary);
|
|
|
|
|
--color-fg-subtle: var(--text-muted);
|
|
|
|
|
--color-fg-inverted: var(--text-inverted);
|
|
|
|
|
|
|
|
|
|
--color-accent: hsl(var(--accent));
|
|
|
|
|
--color-accent-hover: hsl(var(--accent-hover));
|
|
|
|
|
--color-accent-fg: hsl(var(--accent-text));
|
|
|
|
|
--color-accent-subtle: hsl(var(--accent-subtle));
|
|
|
|
|
--color-accent: var(--accent);
|
|
|
|
|
--color-accent-hover: var(--accent-hover);
|
|
|
|
|
--color-accent-fg: var(--accent-text);
|
|
|
|
|
--color-accent-subtle: var(--accent-subtle);
|
|
|
|
|
|
|
|
|
|
--color-healthy: hsl(var(--status-healthy));
|
|
|
|
|
--color-healthy-bg: hsl(var(--status-healthy-bg));
|
|
|
|
|
--color-warning: hsl(var(--status-warning));
|
|
|
|
|
--color-warning-bg: hsl(var(--status-warning-bg));
|
|
|
|
|
--color-high: hsl(var(--status-high));
|
|
|
|
|
--color-high-bg: hsl(var(--status-high-bg));
|
|
|
|
|
--color-critical: hsl(var(--status-critical));
|
|
|
|
|
--color-critical-bg: hsl(var(--status-critical-bg));
|
|
|
|
|
--color-info: hsl(var(--status-info));
|
|
|
|
|
--color-info-bg: hsl(var(--status-info-bg));
|
|
|
|
|
--color-neutral: hsl(var(--status-neutral));
|
|
|
|
|
--color-neutral-bg: hsl(var(--status-neutral-bg));
|
|
|
|
|
--color-healthy: var(--status-healthy);
|
|
|
|
|
--color-healthy-bg: var(--status-healthy-bg);
|
|
|
|
|
--color-warning: var(--status-warning);
|
|
|
|
|
--color-warning-bg: var(--status-warning-bg);
|
|
|
|
|
--color-high: var(--status-high);
|
|
|
|
|
--color-high-bg: var(--status-high-bg);
|
|
|
|
|
--color-critical: var(--status-critical);
|
|
|
|
|
--color-critical-bg: var(--status-critical-bg);
|
|
|
|
|
--color-info: var(--status-info);
|
|
|
|
|
--color-info-bg: var(--status-info-bg);
|
|
|
|
|
--color-neutral: var(--status-neutral);
|
|
|
|
|
--color-neutral-bg: var(--status-neutral-bg);
|
|
|
|
|
|
|
|
|
|
--color-ring: hsl(var(--focus-ring));
|
|
|
|
|
--color-ring: var(--focus-ring);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@layer base {
|
|
|
|
|
* {
|
|
|
|
|
border-color: hsl(var(--border-default));
|
|
|
|
|
border-color: var(--border-default);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
html {
|
|
|
|
|
@ -172,21 +193,22 @@
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body {
|
|
|
|
|
background-color: hsl(var(--surface-page));
|
|
|
|
|
color: hsl(var(--text-primary));
|
|
|
|
|
background-color: var(--surface-page);
|
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
font-family: var(--font-sans);
|
|
|
|
|
-webkit-font-smoothing: antialiased;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Der Fokusring bleibt sichtbar. Ihn zu entfernen macht die Konsole fuer
|
|
|
|
|
* Tastaturbedienung unbrauchbar — und an einer Stoerung arbeitet niemand mit
|
|
|
|
|
/* Der Fokusring bleibt sichtbar. Ihn zu entfernen macht die Konsole für
|
|
|
|
|
* Tastaturbedienung unbrauchbar — und an einer Störung arbeitet niemand mit
|
|
|
|
|
* der Maus. */
|
|
|
|
|
:focus-visible {
|
|
|
|
|
outline: 2px solid hsl(var(--focus-ring));
|
|
|
|
|
outline: 2px solid var(--focus-ring);
|
|
|
|
|
outline-offset: 2px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Zahlen in Tabellen sollen untereinander stehen. */
|
|
|
|
|
/* Bei einer dicktengleichen Schrift stehen Ziffern ohnehin untereinander;
|
|
|
|
|
* die Klasse bleibt, damit die Aufrufstellen unverändert gelten. */
|
|
|
|
|
.tabular {
|
|
|
|
|
font-variant-numeric: tabular-nums;
|
|
|
|
|
}
|
|
|
|
|
|