diff --git a/frontend/index.html b/frontend/index.html
index 2c5762f..5d815bd 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -3,7 +3,22 @@
- SwyxWeb
+ SwyxWeb · STADTBOTE
+
+
+
+
+
+
diff --git a/frontend/src/components/StadtboteSignet.tsx b/frontend/src/components/StadtboteSignet.tsx
new file mode 100644
index 0000000..87f67fb
--- /dev/null
+++ b/frontend/src/components/StadtboteSignet.tsx
@@ -0,0 +1,29 @@
+/**
+ * Das STADTBOTE-Signet aus dem Corporate-Design-Manual: ein offener roter Ring
+ * mit einem „S" in der Mitte. Als Inline-SVG nachgebaut, weil das Brandbook das
+ * Logo nur als Pixelbild enthält; die Farbe kommt über currentColor vom Umfeld.
+ */
+export default function StadtboteSignet({ className }: { className?: string }) {
+ return (
+
+ )
+}
diff --git a/frontend/src/index.css b/frontend/src/index.css
index af44552..df54ff2 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -1,26 +1,48 @@
+/*
+ * Farb- und Schriftvorgaben aus dem STADTBOTE-Styleguide (HANSETRANS Brandbook):
+ * Primär Rot #CA0D38 (Pantone 185 C) und Grau #7C7F7E (Pantone 424 C),
+ * Off-Black #222222 für Fließtext, Grauabstufungen als Flächen.
+ * Schrift: Red Hat Display (Überschriften, Versalien, Laufweite 4 %) und
+ * Red Hat Text (Fließtext). Buttons: primär vollflächig, sekundär mit Rahmen,
+ * Kästen und Linien mit leichter Abrundung.
+ */
:root {
- --bg: #0f1116;
- --surface: #171a21;
- --surface-2: #1f2530;
- --border: #2b3341;
- --text: #e6e9ef;
- --text-muted: #98a2b3;
- --accent: #4f8cff;
- --ok: #35c98a;
- --warn: #e0b341;
- --err: #f2585b;
- color-scheme: dark;
+ --bg: #ffffff;
+ --surface: #ffffff;
+ --surface-2: #f6f6f6;
+ --border: #dcdcdd;
+ --border-strong: #b4b4b5;
+ --text: #222222;
+ --text-muted: #7c7f7e;
+ /* Vollflächen (Buttons, Balken) – immer das Markenrot mit weißer Schrift. */
+ --brand: #ca0d38;
+ --brand-strong: #a30a2d;
+ --brand-soft: rgb(202 13 56 / 8%);
+ /* Rot als Text- und Konturfarbe; im Dunkelmodus eine hellere Abstufung. */
+ --accent: #ca0d38;
+ --ok: #2f9e6e;
+ --warn: #b98a1c;
+ --err: #d92b1f;
+ color-scheme: light;
}
-@media (prefers-color-scheme: light) {
+@media (prefers-color-scheme: dark) {
:root {
- --bg: #f5f7fa;
- --surface: #ffffff;
- --surface-2: #eef1f6;
- --border: #d8dee9;
- --text: #1b2230;
- --text-muted: #5c6779;
- color-scheme: light;
+ --bg: #17181a;
+ --surface: #1f2023;
+ --surface-2: #28292d;
+ --border: #3a3b40;
+ --border-strong: #55565c;
+ --text: #f1f1f2;
+ --text-muted: #a4a7a8;
+ --brand: #ca0d38;
+ --brand-strong: #e33e60;
+ --brand-soft: rgb(227 62 96 / 14%);
+ --accent: #ef7d95;
+ --ok: #43c78f;
+ --warn: #e0b341;
+ --err: #f2665b;
+ color-scheme: dark;
}
}
@@ -32,9 +54,21 @@ body {
margin: 0;
background: var(--bg);
color: var(--text);
- font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
+ font-family: 'Red Hat Text', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
font-size: 15px;
- line-height: 1.5;
+ line-height: 1.4;
+}
+
+h1,
+h2,
+h3 {
+ /* Überschriften laut Styleguide: Red Hat Display Semibold in Versalien,
+ Laufweite 4 %, Zeilenabstand 100 %. */
+ font-family: 'Red Hat Display', 'Red Hat Text', system-ui, sans-serif;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ line-height: 1;
}
code {
@@ -59,14 +93,38 @@ code {
flex-wrap: wrap;
}
-.page__header h1 {
+/* Abgerundete Linie als Trennlinie unter dem Kopf – Gestaltungselement des CI. */
+.page__header::after {
+ content: '';
+ flex-basis: 100%;
+ height: 3px;
+ border-radius: 999px;
+ background: var(--brand);
+}
+
+.brand {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ color: var(--accent);
+}
+
+.brand__signet {
+ width: 46px;
+ height: 46px;
+ flex: 0 0 auto;
+}
+
+.brand__name {
margin: 0;
- font-size: 26px;
- letter-spacing: -0.02em;
+ font-weight: 700;
+ font-size: 24px;
+ letter-spacing: 0.06em;
+ color: var(--accent);
}
.page__subtitle {
- margin: 2px 0 0;
+ margin: 4px 0 0;
color: var(--text-muted);
}
@@ -84,7 +142,7 @@ code {
.card {
background: var(--surface);
border: 1px solid var(--border);
- border-radius: 12px;
+ border-radius: 8px;
padding: 18px;
display: flex;
flex-direction: column;
@@ -93,8 +151,8 @@ code {
.card h2 {
margin: 0;
- font-size: 16px;
- font-weight: 600;
+ font-size: 15px;
+ color: var(--text);
}
.card__header {
@@ -134,9 +192,9 @@ code {
.field__input {
width: 100%;
padding: 9px 12px;
- border-radius: 8px;
- border: 1px solid var(--border);
- background: var(--surface-2);
+ border-radius: 6px;
+ border: 1px solid var(--border-strong);
+ background: var(--surface);
color: var(--text);
font: inherit;
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
@@ -144,27 +202,30 @@ code {
}
.field__input:focus {
- outline: 2px solid var(--accent);
+ outline: 2px solid var(--brand);
outline-offset: 1px;
+ border-color: var(--brand);
}
.field__input:disabled {
opacity: 0.55;
+ background: var(--surface-2);
}
+/* Sekundärbutton laut Styleguide: schlichter roter Rahmen, leichte Abrundung. */
.button {
padding: 9px 16px;
- border-radius: 8px;
- border: 1px solid var(--border);
- background: var(--surface-2);
- color: var(--text);
+ border-radius: 6px;
+ border: 1px solid var(--accent);
+ background: transparent;
+ color: var(--accent);
font: inherit;
font-weight: 500;
cursor: pointer;
}
.button:hover:not(:disabled) {
- border-color: var(--accent);
+ background: var(--brand-soft);
}
.button:disabled {
@@ -172,13 +233,20 @@ code {
cursor: not-allowed;
}
+/* Primärbutton laut Styleguide: vollflächig im Markenrot. */
.button--primary {
- background: var(--accent);
- border-color: var(--accent);
+ background: var(--brand);
+ border-color: var(--brand);
color: #fff;
}
+.button--primary:hover:not(:disabled) {
+ background: var(--brand-strong);
+ border-color: var(--brand-strong);
+}
+
.button--ghost {
+ border-color: transparent;
background: transparent;
padding: 5px 10px;
font-size: 13px;
@@ -200,21 +268,25 @@ code {
.tabs {
display: flex;
- gap: 4px;
+ gap: 18px;
border-bottom: 1px solid var(--border);
+ flex-wrap: wrap;
}
.tabs__button {
- padding: 9px 16px;
- border: 1px solid transparent;
- /* Die aktive Kante überdeckt die Linie der Leiste. */
- border-bottom: none;
+ padding: 10px 2px;
+ border: none;
+ border-bottom: 3px solid transparent;
margin-bottom: -1px;
- border-radius: 10px 10px 0 0;
+ border-radius: 0;
background: transparent;
color: var(--text-muted);
font: inherit;
- font-weight: 500;
+ font-family: 'Red Hat Display', 'Red Hat Text', system-ui, sans-serif;
+ font-weight: 600;
+ font-size: 13px;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
cursor: pointer;
}
@@ -223,9 +295,8 @@ code {
}
.tabs__button--active {
- background: var(--surface);
- border-color: var(--border);
- color: var(--text);
+ color: var(--accent);
+ border-bottom-color: var(--brand);
}
[role='tabpanel'] {
@@ -354,7 +425,12 @@ code {
.button--accept {
background: var(--ok);
border-color: var(--ok);
- color: #06281c;
+ color: #fff;
+}
+
+.button--accept:hover:not(:disabled) {
+ background: var(--ok);
+ opacity: 0.9;
}
.button--reject {
@@ -363,6 +439,11 @@ code {
color: #fff;
}
+.button--reject:hover:not(:disabled) {
+ background: var(--err);
+ opacity: 0.9;
+}
+
.button--small {
padding: 5px 12px;
font-size: 13px;
@@ -387,7 +468,7 @@ code {
gap: 12px;
flex-wrap: wrap;
padding: 10px 12px;
- border-radius: 8px;
+ border-radius: 6px;
border: 1px solid var(--border);
background: var(--surface-2);
}
@@ -400,7 +481,7 @@ code {
.history__line {
flex: 0 0 auto;
padding: 2px 8px;
- border-radius: 6px;
+ border-radius: 4px;
background: var(--border);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 12px;
@@ -463,8 +544,8 @@ code {
}
.history__badge--ended {
- border-color: var(--err);
- color: var(--err);
+ border-color: var(--border-strong);
+ color: var(--text-muted);
}
.history__number {
@@ -492,7 +573,7 @@ code {
align-items: center;
gap: 12px;
padding: 10px 12px;
- border-radius: 8px;
+ border-radius: 6px;
border: 1px solid var(--border);
background: var(--surface-2);
}
@@ -504,7 +585,7 @@ code {
.tablist__id {
flex: 0 0 auto;
padding: 2px 8px;
- border-radius: 6px;
+ border-radius: 4px;
background: var(--border);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 12px;
@@ -561,15 +642,15 @@ code {
.dialog {
width: min(420px, 100%);
padding: 24px;
- border-radius: 12px;
+ border-radius: 8px;
border: 1px solid var(--border);
background: var(--surface);
- box-shadow: 0 24px 60px rgb(0 0 0 / 45%);
+ box-shadow: 0 24px 60px rgb(0 0 0 / 25%);
}
.dialog__title {
margin: 0 0 16px;
- font-size: 18px;
+ font-size: 17px;
}
.dialog__status {
@@ -591,14 +672,15 @@ code {
.progress {
height: 8px;
border-radius: 999px;
- background: var(--border);
+ background: var(--surface-2);
+ border: 1px solid var(--border);
overflow: hidden;
}
.progress__bar {
height: 100%;
border-radius: 999px;
- background: var(--accent);
+ background: var(--brand);
transition: width 120ms linear;
}
@@ -634,7 +716,7 @@ code {
align-items: center;
gap: 12px;
padding: 10px 12px;
- border-radius: 8px;
+ border-radius: 6px;
border: 1px solid var(--border);
background: var(--surface-2);
}
@@ -672,7 +754,7 @@ code {
height: 300px;
overflow-y: auto;
padding: 12px;
- border-radius: 8px;
+ border-radius: 6px;
border: 1px solid var(--border);
background: var(--surface-2);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
@@ -732,7 +814,7 @@ code {
flex-direction: column;
gap: 8px;
padding: 10px 12px;
- border-radius: 8px;
+ border-radius: 6px;
border: 1px solid var(--border);
background: var(--surface-2);
}
@@ -753,7 +835,7 @@ code {
.webhook__id {
padding: 1px 8px;
- border-radius: 6px;
+ border-radius: 4px;
background: var(--border);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 12px;
@@ -772,7 +854,7 @@ code {
.webhook__json {
margin: 0;
padding: 10px 12px;
- border-radius: 6px;
+ border-radius: 4px;
background: var(--surface);
border: 1px solid var(--border);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
@@ -789,8 +871,8 @@ code {
margin-left: 8px;
padding: 1px 7px;
border-radius: 999px;
- background: var(--accent);
- color: var(--surface);
+ background: var(--brand);
+ color: #fff;
font-size: 12px;
font-weight: 700;
font-variant-numeric: tabular-nums;
diff --git a/frontend/src/pages/HomePage.tsx b/frontend/src/pages/HomePage.tsx
index 06d0a5c..9579331 100644
--- a/frontend/src/pages/HomePage.tsx
+++ b/frontend/src/pages/HomePage.tsx
@@ -5,6 +5,7 @@ import { useCallNotifications } from '../hooks/useCallNotifications'
import { useWebhook } from '../hooks/useWebhook'
import { countUnseen } from '../webhook'
import StatusBadge from '../components/StatusBadge'
+import StadtboteSignet from '../components/StadtboteSignet'
import MessageLog from '../components/MessageLog'
import IncomingCallCard from '../components/IncomingCallCard'
import DialPanel from '../components/DialPanel'
@@ -99,9 +100,12 @@ export default function HomePage() {
return (