Quellcode des ICON CRM (6)

This commit is contained in:
2026-09-14 16:55:40 +02:00
parent 4fcb34f324
commit bd810fa608
24 changed files with 3855 additions and 0 deletions
+652
View File
@@ -0,0 +1,652 @@
@import 'tailwindcss';
/*
* ICON CRM - Corporate Identity
*
* Primaerfarbe #C1862F (Gold), heller Akzent #DFA85A
* Flaechen neutrales Grau bis #0A0A0A im Dunkelmodus
* Schrift Montserrat
*
* Aufbau wie im perinco CRM: im Markup steht nirgends eine feste Farbe,
* sondern durchgaengig brand-*, ink-*, canvas und surface. Ein Moduswechsel
* oder ein Design tauscht deshalb nur Variablenwerte - die Komponenten
* brauchen keine dark:-Varianten.
*
* Die Rollen der Skalen sind ueberall gleich:
* ink-50/100 Flaechen und Hover
* ink-200 Rahmen
* ink-300-900 Text; 400 traegt die Hinweistexte
* ink-950 liegt nur unter Dialog-Overlays, bleibt immer dunkel
* brand-50/100 getoente Flaechen
* brand-200-400 Rahmen und Akzente
* brand-500 das CI-Gold - Logo, aktive Kanten, Fokusring
* brand-600 gefuellte Knoepfe; hier steht WEISSE Schrift drauf, deshalb
* dunkler als 500 (Kontrast 4.8:1 statt 2.9:1)
* brand-700-900 Text auf getoenten Flaechen
*/
@theme {
--font-sans: 'Montserrat', ui-sans-serif, system-ui, sans-serif;
--font-display: 'Montserrat', ui-sans-serif, system-ui, sans-serif;
/* Flaechen semantisch benannt statt "weiss" - im Dunkelmodus werden nur
diese Werte getauscht. */
--color-canvas: #f6f6f7;
--color-surface: #ffffff;
--color-brand-50: #fdf8f0;
--color-brand-100: #f8ecd8;
--color-brand-200: #efd8ae;
--color-brand-300: #e3bd7c;
--color-brand-400: #d3a253;
--color-brand-500: #c1862f;
--color-brand-600: #a06c22;
--color-brand-700: #7d541b;
--color-brand-800: #5f4116;
--color-brand-900: #48310f;
--color-brand-accent: #dfa85a;
--color-ink-50: #f7f7f8;
--color-ink-100: #ededef;
--color-ink-200: #dcdce0;
--color-ink-300: #bcbcc2;
--color-ink-400: #93939b;
--color-ink-500: #6b6b73;
--color-ink-600: #55555c;
--color-ink-700: #414147;
--color-ink-800: #2b2b30;
--color-ink-900: #1a1a1a;
--color-ink-950: #0a0a0a;
--shadow-card: 0 1px 2px rgb(10 10 10 / 0.04), 0 4px 16px rgb(10 10 10 / 0.06);
--shadow-lift: 0 8px 28px rgb(10 10 10 / 0.12);
}
/*
* Dunkelmodus. Die neutrale Skala wird gedreht: 50 ist die dunkelste Flaeche,
* 900 der hellste Text.
*
* Zwei Werte bleiben in beiden Modi gleich und sind deshalb bewusst so
* gewaehlt: ink-950 liegt nur unter Dialog-Overlays und muss dunkel bleiben,
* und text-white steht immer auf farbigen Flaechen.
*/
.dark {
--color-canvas: #0a0a0a;
--color-surface: #161616;
--color-ink-50: #1c1c1e;
--color-ink-100: #26262a;
--color-ink-200: #36363c;
/* Nicht die exakte Umkehrung von #bcbcc2 - dunkler waeren die Hinweistexte
(text-ink-300) auf der Flaeche kaum noch zu lesen. */
--color-ink-300: #6b6b73;
--color-ink-400: #90909a;
--color-ink-500: #a9a9b2;
--color-ink-600: #bfbfc6;
--color-ink-700: #d4d4d9;
--color-ink-800: #e7e7ea;
--color-ink-900: #f6f6f7;
--color-ink-950: #000000;
/* Das Gold bleibt das Gold. Die hellen Stufen werden zu dunklen Toenen
(Flaechen), die dunklen zu hellen (Text). 600 traegt weiter die gefuellten
Knoepfe, darf hier aber heller sein - auf Schwarz leuchtet es sonst nicht. */
--color-brand-50: #2a1e0a;
--color-brand-100: #3a290d;
--color-brand-200: #5a3f15;
--color-brand-300: #7d541b;
--color-brand-400: #a87428;
--color-brand-600: #d0953c;
--color-brand-700: #e3bd7c;
--color-brand-800: #efd8ae;
--color-brand-900: #f8ecd8;
/* Getoente Status-Pillen: hell mit dunklem Text wird hier gedreht. Die
Stufen 500/600 bleiben unberuehrt, dort steht weisse Schrift drauf. */
--color-sky-50: #0d2537;
--color-sky-200: #1d4a6b;
--color-sky-700: #7cc4ef;
--color-emerald-50: #0b2a1e;
--color-emerald-200: #14513a;
--color-emerald-700: #6ee7b7;
--color-amber-50: #2e2008;
--color-amber-200: #5c4210;
--color-amber-700: #f0b356;
--color-violet-50: #241a3d;
--color-violet-200: #3f2f66;
--color-violet-700: #b49bf2;
--color-red-50: #2e1414;
--color-red-200: #5e2626;
--color-red-700: #f28b8b;
}
/* ===========================================================================
* Half-Life
*
* Black Mesa: Beton, Warnorange und harte Kanten. Der Akzent ist das Orange des
* HEV-Anzugs, die Flächen sind Sichtbeton mit kaltem Stich, die Ecken fast
* rechtwinklig - Laboreinrichtung hat keine Radien.
*
* Zwei Dinge sind bewusst so gelöst:
*
* * Der Akzent bleibt Orange und wird nicht zu Gelb. Auf brand-500 und
* brand-600 steht überall weiße Schrift; ein helleres Warngelb wäre dort
* nicht mehr lesbar. Das Gelb-Schwarz der Gefahrenstreifen kommt deshalb
* nicht als Fläche vor.
* * Die Überschriften laufen in Oswald und gesperrt in Versalien - eine
* schmale Grotesk ist das, was die Beschilderung in Black Mesa ausmacht.
* Der Fließtext bleibt Montserrat: die Akquise-Tabellen haben acht Spalten
* bei 12 px, und eine Schmalschrift wäre darin nicht mehr zu lesen.
*
* Der helle Block ist mit :not(.dark) abgegrenzt. Ohne das gewänne er gegen
* .dark (eine Klasse mehr in der Spezifität) und der Dunkelmodus wäre kaputt.
* =========================================================================== */
html.theme-halflife:not(.dark) {
/*
* Grafik hinter Kopfleiste und Menü.
*
* Die Variable enthält ZWEI Ebenen: einen Schleier aus der Flächenfarbe und
* darunter die Zeichnung. Das ist kein Umweg, sondern der Grund, dass
* dieselbe Grafik in hell und dunkel funktioniert - und die Bedingung dafür,
* dass die Schrift lesbar bleibt. In der Kopfleiste steht der Schleier an den
* Rändern dicht (Titel links, Knöpfe rechts) und lässt die Grafik nur in der
* Mitte durch; im Menü liegt er oben über den Einträgen und gibt nach unten
* frei.
*/
--theme-header-image: linear-gradient(
90deg,
rgb(244 242 236 / 0.96) 0%,
rgb(244 242 236 / 0.55) 28%,
rgb(244 242 236 / 0.5) 55%,
rgb(244 242 236 / 0.96) 100%
),
url('/themes/halflife-header.svg');
--theme-sidebar-image: linear-gradient(
180deg,
rgb(244 242 236 / 0.98) 0%,
rgb(244 242 236 / 0.93) 45%,
rgb(244 242 236 / 0.62) 78%,
rgb(244 242 236 / 0.72) 100%
),
url('/themes/halflife-sidebar.svg');
/* Laborflur: Sichtbeton, kalt-warm gemischt. Deutlich dunkler als die Karten,
damit die Panels wie eingesetzte Platten wirken. */
--color-canvas: #dedbd3;
--color-surface: #f4f2ec;
--color-brand-50: #fdf1e5;
--color-brand-100: #fae0c6;
--color-brand-200: #f4bf8a;
--color-brand-300: #ec9c4f;
--color-brand-400: #e5811f;
--color-brand-500: #e0720b;
/* Gefüllte Knöpfe tragen weiße Schrift - dieser Ton hält den Kontrast. */
--color-brand-600: #b85a05;
--color-brand-700: #8f4604;
--color-brand-800: #6a3403;
--color-brand-900: #4b2502;
--color-brand-accent: #ff8c1a;
/* Stahlgrau mit kaltem Stich statt Neutralgrau. */
--color-ink-50: #eceae4;
--color-ink-100: #dedbd3;
--color-ink-200: #bfbcb2;
--color-ink-300: #98958b;
/* Hinweistexte (text-ink-400) müssen auf dem Beton lesbar bleiben -
deshalb dunkler als die reine Umkehrung. */
--color-ink-400: #6b6961;
--color-ink-500: #55534c;
--color-ink-600: #44423c;
--color-ink-700: #35332e;
--color-ink-800: #26241f;
--color-ink-900: #171512;
--color-ink-950: #0b0a08;
/* Kanten wie an Laboreinrichtung: fast rechtwinklig. */
--radius-sm: 0.0625rem;
--radius-md: 0.0625rem;
--radius-lg: 0.125rem;
--radius-xl: 0.125rem;
--radius-2xl: 0.1875rem;
/* Hart und versetzt statt weich - Beton wirft keinen weichen Schatten. */
--shadow-card: 0 1px 0 0 rgb(23 21 18 / 0.12), 2px 2px 0 0 rgb(23 21 18 / 0.06);
--shadow-lift: 4px 4px 0 0 rgb(23 21 18 / 0.18);
--font-display: 'Oswald', 'Montserrat', ui-sans-serif, system-ui, sans-serif;
}
/*
* Half-Life, dunkel: Ravenholm. Die Flächen sind nicht neutral schwarz, sondern
* ins Blaugrün gezogen; das Orange leuchtet kräftiger, weil es die einzige
* warme Farbe im Bild ist.
*/
html.theme-halflife.dark {
/* Dieselbe Zeichnung, dunkler Schleier: aus dem Laborflur wird Nachtschicht. */
--theme-header-image: linear-gradient(
90deg,
rgb(22 28 31 / 0.96) 0%,
rgb(22 28 31 / 0.62) 28%,
rgb(22 28 31 / 0.55) 55%,
rgb(22 28 31 / 0.96) 100%
),
url('/themes/halflife-header.svg');
--theme-sidebar-image: linear-gradient(
180deg,
rgb(22 28 31 / 0.97) 0%,
rgb(22 28 31 / 0.9) 45%,
rgb(22 28 31 / 0.55) 78%,
rgb(22 28 31 / 0.68) 100%
),
url('/themes/halflife-sidebar.svg');
--color-canvas: #0d1113;
--color-surface: #161c1f;
--color-brand-50: #2a1608;
--color-brand-100: #3a1e0a;
--color-brand-200: #5c3010;
--color-brand-300: #7d4315;
--color-brand-400: #b25f1c;
--color-brand-500: #e0720b;
--color-brand-600: #ff8c1a;
--color-brand-700: #f4bf8a;
--color-brand-800: #fae0c6;
--color-brand-900: #fdf1e5;
--color-brand-accent: #ff8c1a;
--color-ink-50: #191f22;
--color-ink-100: #222a2e;
--color-ink-200: #33403f;
--color-ink-300: #667470;
--color-ink-400: #8b9894;
--color-ink-500: #a6b2ae;
--color-ink-600: #bfc9c5;
--color-ink-700: #d5dcd9;
--color-ink-800: #e8edeb;
--color-ink-900: #f5f8f7;
--color-ink-950: #000000;
--radius-sm: 0.0625rem;
--radius-md: 0.0625rem;
--radius-lg: 0.125rem;
--radius-xl: 0.125rem;
--radius-2xl: 0.1875rem;
--shadow-card: 0 0 0 1px rgb(224 114 11 / 0.1), 2px 2px 0 0 rgb(0 0 0 / 0.5);
--shadow-lift: 4px 4px 0 0 rgb(0 0 0 / 0.6);
--font-display: 'Oswald', 'Montserrat', ui-sans-serif, system-ui, sans-serif;
/* Die getönten Status-Pillen aus .dark ins Kalte gezogen. */
--color-amber-50: #2b1e05;
--color-amber-200: #573d0c;
--color-emerald-50: #0a2620;
--color-emerald-200: #14493c;
}
/* ===========================================================================
* Pixel Art
*
* 8-bit: keine runden Ecken, harte versetzte Schatten ohne Weichzeichnung,
* Rahmen als dunkle Outline, gesättigtes Arcade-Grün.
*
* Die Pixelschrift steckt nur in --font-display (Überschriften und
* Feldbeschriftungen). Der Fließtext bleibt Montserrat: die Tabellen haben bis
* zu acht Spalten bei 12 px, und eine Pixelschrift wäre darin nicht mehr zu
* lesen - ein Design, das die Arbeit behindert, wäre ein schlechtes Design.
* =========================================================================== */
html.theme-pixel:not(.dark) {
--theme-header-image: linear-gradient(
90deg,
rgb(246 248 241 / 0.95) 0%,
rgb(246 248 241 / 0.45) 30%,
rgb(246 248 241 / 0.4) 55%,
rgb(246 248 241 / 0.95) 100%
),
url('/themes/pixel-header.svg');
--theme-sidebar-image: linear-gradient(
180deg,
rgb(246 248 241 / 0.97) 0%,
rgb(246 248 241 / 0.92) 48%,
rgb(246 248 241 / 0.7) 80%,
rgb(246 248 241 / 0.8) 100%
),
url('/themes/pixel-sidebar.svg');
/* Deutlich dunkler als die Karten: Pixelgrafik lebt von harten Kanten, und
bei zu ähnlichen Tönen verschwimmen Karte und Grund. */
--color-canvas: #cdd8c2;
--color-surface: #f6f8f1;
--color-brand-50: #e0f2d4;
--color-brand-100: #c8e8b4;
/* Rahmen sind hier keine Andeutung, sondern Kontur - deshalb dunkel. */
--color-brand-200: #2b7a1c;
--color-brand-300: #256b18;
--color-brand-400: #35931f;
--color-brand-500: #2e8b22;
--color-brand-600: #24701a;
--color-brand-700: #1b5613;
--color-brand-800: #143f0e;
--color-brand-900: #0e2f0a;
--color-brand-accent: #2e8b22;
--color-ink-50: #eef2e8;
--color-ink-100: #dde4d4;
/* Der Kniff des Designs: ink-200 ist fast ausschließlich Rahmen und wird hier
zur schwarzen Outline - an allen Stellen zugleich, ohne eine Zeile Markup. */
--color-ink-200: #1f2a1a;
--color-ink-300: #5a6653;
--color-ink-400: #47523f;
--color-ink-500: #38412f;
--color-ink-600: #2c3425;
--color-ink-700: #22291c;
--color-ink-800: #182015;
--color-ink-900: #0e140c;
--color-ink-950: #000000;
--radius-sm: 0;
--radius-md: 0;
--radius-lg: 0;
--radius-xl: 0;
--radius-2xl: 0;
/* Versetzt statt weichgezeichnet - so sehen Schatten in Pixelgrafik aus. */
--shadow-card: 4px 4px 0 0 #1f2a1a;
--shadow-lift: 6px 6px 0 0 #1f2a1a;
--font-display: 'Silkscreen', 'Courier New', ui-monospace, monospace;
}
/*
* Pixel Art, dunkel: Arcade-Automat im dunklen Raum. Flächen fast schwarz mit
* blauem Stich, Konturen in gedecktem Grün - schwarze Outlines wären auf
* schwarzem Grund unsichtbar.
*/
html.theme-pixel.dark {
--theme-header-image: linear-gradient(
90deg,
rgb(21 26 34 / 0.96) 0%,
rgb(21 26 34 / 0.7) 30%,
rgb(21 26 34 / 0.62) 55%,
rgb(21 26 34 / 0.96) 100%
),
url('/themes/pixel-header.svg');
--theme-sidebar-image: linear-gradient(
180deg,
rgb(21 26 34 / 0.97) 0%,
rgb(21 26 34 / 0.92) 48%,
rgb(21 26 34 / 0.76) 80%,
rgb(21 26 34 / 0.86) 100%
),
url('/themes/pixel-sidebar.svg');
--color-canvas: #0d0f14;
--color-surface: #151a22;
--color-brand-50: #0f2a0c;
--color-brand-100: #163c11;
--color-brand-200: #2c7a1f;
--color-brand-300: #35931f;
--color-brand-400: #3aa524;
--color-brand-500: #3aa524;
--color-brand-600: #49bf30;
--color-brand-700: #7fdc63;
--color-brand-800: #b0ec9c;
--color-brand-900: #d8f7cd;
--color-brand-accent: #49bf30;
--color-ink-50: #1a2029;
--color-ink-100: #232b36;
--color-ink-200: #33734a;
--color-ink-300: #6f7f92;
--color-ink-400: #93a3b5;
--color-ink-500: #adbccb;
--color-ink-600: #c2cfdb;
--color-ink-700: #d6e0ea;
--color-ink-800: #e9eff5;
--color-ink-900: #f6f9fc;
--color-ink-950: #000000;
--radius-sm: 0;
--radius-md: 0;
--radius-lg: 0;
--radius-xl: 0;
--radius-2xl: 0;
--shadow-card: 4px 4px 0 0 #000000;
--shadow-lift: 6px 6px 0 0 #000000;
--font-display: 'Silkscreen', 'Courier New', ui-monospace, monospace;
}
@layer base {
html,
body {
height: 100%;
}
body {
background-color: var(--color-canvas);
color: var(--color-ink-900);
font-family: var(--font-sans);
font-weight: 400;
-webkit-font-smoothing: antialiased;
transition:
background-color 0.2s ease,
color 0.2s ease;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: var(--font-display);
font-weight: 700;
letter-spacing: -0.015em;
}
/* Feldbeschriftungen tragen dieselbe Klasse, damit ein spaeteres Design sie
mit einer Regel erreicht. */
.field-label {
font-family: var(--font-display);
}
/* Fokus-Ring durchgaengig im CI-Gold */
:focus-visible {
outline: 2px solid var(--color-brand-500);
outline-offset: 2px;
}
/*
* Half-Life: Überschriften und Feldbeschriftungen laufen gesperrt in
* Versalien - so ist Black Mesa beschildert. Die negative Laufweite der
* Grundeinstellung würde Oswald ineinanderschieben.
*/
html.theme-halflife h1,
html.theme-halflife h2,
html.theme-halflife h3,
html.theme-halflife h4,
html.theme-halflife h5,
html.theme-halflife h6 {
letter-spacing: 0.04em;
text-transform: uppercase;
font-weight: 600;
}
html.theme-halflife .field-label {
letter-spacing: 0.12em;
}
/*
* Pixelschrift hat eine feste Zeichenbreite und trägt ihre Sperrung selbst;
* die negative Laufweite der Überschriften würde die Buchstaben ineinander
* schieben. Außerdem kein Kantenglätten - Pixel sollen Pixel bleiben.
*/
html.theme-pixel h1,
html.theme-pixel h2,
html.theme-pixel h3,
html.theme-pixel h4,
html.theme-pixel h5,
html.theme-pixel h6,
html.theme-pixel .field-label {
letter-spacing: 0;
-webkit-font-smoothing: none;
}
/*
* Hintergrundbilder der Kopfleiste und des Menüs.
*
* Ohne Design steht in den Variablen nichts, dann greift der Rückfall `none`
* und beide Flächen bleiben einfarbig - ICON sieht also aus wie immer.
* `bg-surface` an den Elementen bleibt: die Farbe liegt unter dem Bild und
* trägt, solange die Grafik lädt oder fehlt.
*/
.app-header {
background-image: var(--theme-header-image, none);
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}
.app-sidebar {
background-image: var(--theme-sidebar-image, none);
background-repeat: no-repeat;
/* Unten verankert: dort sitzt in beiden Grafiken das Motiv. */
background-position: bottom center;
background-size: cover;
}
}
@layer utilities {
/*
* "rounded-full" lässt sich nicht über eine Variable abschalten - Tailwind
* schreibt dort einen festen Wert. Für Pixel Art muss es aber weg: runde
* Punkte und Pillen neben eckigen Karten wären ein Bruch. Der
* Attributselektor greift genau dieses eine Klassenwort und ist mit dem
* vorangestellten html spezifischer als die Utility-Klasse.
*/
html.theme-pixel [class~='rounded-full'] {
border-radius: 0;
}
}
@layer utilities {
/* Das ICON Logo ist fuer helle Hintergruende gemacht - im Dunkelmodus wird
die Helligkeit gedreht und das Gold per hue-rotate zurueckgeholt. */
.dark .logo-adaptive {
filter: invert(1) hue-rotate(180deg);
}
.scrollbar-slim::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.scrollbar-slim::-webkit-scrollbar-track {
background: transparent;
}
.scrollbar-slim::-webkit-scrollbar-thumb {
background: var(--color-ink-200);
border-radius: 999px;
}
.scrollbar-slim::-webkit-scrollbar-thumb:hover {
background: var(--color-ink-300);
}
/*
* Der WYSIWYG-Editor und die Leseansicht der Ausschreibungstexte.
*
* Tailwind setzt Ueberschriften und Listen im Basis-Reset zurueck - in einem
* Feld, dessen Inhalt aus <h2>, <ul> und <p> besteht, saehe sonst alles
* gleich aus. Hier bekommen diese Elemente ihre Darstellung zurueck, und nur
* hier.
*/
/*
* Der Altbestand traegt Inline-Farben aus dem frueheren Editor. Sie hier
* auszuhebeln ist kein Schoenheitseingriff: im Dunkelmodus stuende sonst
* schwarze Schrift auf weissen Kaesten mitten auf dunklem Grund.
*
* !important ist noetig, weil Inline-Stile sonst immer gewinnen. Eigene
* Farbwahl gibt es in diesem Editor nicht - es geht also nichts verloren.
*/
.prose-editor [style] {
color: inherit !important;
background-color: transparent !important;
font-family: inherit !important;
font-size: inherit !important;
}
/*
* Lange Woerter und Adressen muessen umbrechen duerfen. Der Altbestand ist
* voller geschuetzter Leerzeichen; bis ein Text einmal gespeichert und dabei
* bereinigt wurde, haelt das hier die Zeilen im Rahmen.
*/
.prose-editor {
overflow-wrap: anywhere;
word-break: break-word;
}
.prose-editor:empty::before {
content: attr(data-placeholder);
color: var(--color-ink-400);
}
.prose-editor h2 {
font-size: 1.05rem;
font-weight: 700;
margin: 0.9em 0 0.3em;
}
.prose-editor h3 {
font-size: 0.95rem;
font-weight: 600;
margin: 0.8em 0 0.25em;
}
.prose-editor p {
margin: 0.4em 0;
}
.prose-editor ul,
.prose-editor ol {
margin: 0.4em 0 0.4em 1.25em;
}
.prose-editor ul {
list-style: disc;
}
.prose-editor ol {
list-style: decimal;
}
.prose-editor li {
margin: 0.15em 0;
}
/* Ein Aufzaehlungspunkt, der nur eine weitere Liste enthaelt, bekommt kein
eigenes Zeichen - sonst stehen zwei nebeneinander. */
.prose-editor li:has(> ul):not(:has(> :not(ul))),
.prose-editor li:has(> ol):not(:has(> :not(ol))) {
list-style: none;
}
.prose-editor strong {
font-weight: 600;
}
.prose-editor > :first-child {
margin-top: 0;
}
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.line-clamp-3 {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
}