/* TechWaWi — Gestaltungs-Vertrag
   ===========================================================================
   WARUM ES DIESE DATEI GIBT. ERP und Olymp sind zwei getrennte Oberflaechen,
   die derselbe Mensch abwechselnd bedient. Gemessen liegen ihre Paletten
   bereits auf derselben Helligkeitsleiter -- Seitenhintergrund 96,4 % in
   beiden, Canvas 94,1 gegen 94,2, Fliesstext 22,6 gegen 23,3. Sie
   unterscheiden sich fast nur im Farbton: Gruen 128,7 Grad hier, Gold 89,4
   Grad drueben. Diese Datei macht daraus einen Vertrag: gleiche Rollennamen
   in beiden Systemen, unterschiedliche Werte. Was einmal gegen --u-* gebaut
   wird, laesst sich in beiden benutzen.

   WIE SIE WIRKT. Sie wird NACH app.css geladen. Der Bruecken-Block ganz unten
   haengt die alten Tokennamen auf den Vertrag um. Custom Properties loesen zur
   Berechnungszeit auf, nicht beim Parsen -- alle 58 var(--accent), 37
   var(--text-muted) und 32 var(--radius-sm) in app.css zeigen unveraendert
   weiter und bekommen ab hier ihre Werte von hier. Kein Suchen-und-Ersetzen
   in 2132 Zeilen noetig.

   NULLDIFF. Jede oklch-Angabe im Aufsatz ist aus dem bisherigen Hex-Wert
   zurueckgerechnet: Helligkeit und Saettigung bleiben, nur der Farbton wird
   auf den gemeinsamen Regler gelegt. Nachgerechnet ergeben 9 der 13 Rollen
   exakt denselben sRGB-Wert, die anderen vier weichen um eine Einheit in
   einem Kanal ab. Zwei Farben bleiben bewusst Literal, weil sie aus der
   Reihe fallen -- siehe dort.

   KEIN @layer. Nicht gelayertes CSS schlaegt jedes gelayerte; app.css wuerde
   gegen die Tokens gewinnen. Es bleibt bei schlichter Ladereihenfolge.
   =========================================================================== */

:root {
  /* ── Die zwei Regler ──────────────────────────────────────────────────
     Farbton der Neutralen und der Marke. Sie zu drehen tint das ganze
     System um, ohne dass eine Helligkeit oder Saettigung sich aendert.
     Gemessener Median der heutigen Neutralen: 128,7. Akzent: 133,7. */
  --u-h-neut:  128.7;
  --u-h-brand: 133.7;

  /* ── Flaechen ─────────────────────────────────────────────────────── */
  --u-surface:        #ffffff;                 /* Karte, Fensterkoerper, Feld */
  --u-surface-2:      #f2f4ef;   /* Seite */
  --u-surface-3:      #e9ede4;   /* Canvas, eingesenkt */
  --u-surface-alt:    #f6f8f3;   /* Panel */
  --u-field-off:      #f4f6f1;   /* deaktiviertes Feld */

  /* Dunkle Huelle. --u-surface-inv bleibt LITERAL: der Wert liegt bei
     Farbton 148,9 und damit 20 Grad neben allen anderen Neutralen. Auf den
     gemeinsamen Regler gezogen waere er um 3 sRGB-Einheiten heller und
     merklich weniger gruen. Ob das ein Fehler oder Absicht war, entscheidet
     der Betreiber am Schirm -- bis dahin bleibt er, wie er ist. */
  --u-surface-inv:    #0f1610;                 /* Desktop-Grund */
  --u-surface-inv-2:  #1c2118;   /* Kopfleiste, Fenstertitel */

  /* ── Linien ───────────────────────────────────────────────────────── */
  --u-border:         #dde3d7;
  --u-border-strong:  #cfd6c8;
  --u-line-on-inv:    rgba(255, 255, 255, .07);   /* in Olymp identisch */

  /* Haarlinie und Glanzkante. Neu und in Etappe 1 noch ungenutzt -- ab
     Etappe 3 tragen sie die Tiefe, die heute aus Weichzeichnerschatten
     kommt. Ueber color-mix gegen die Flaeche, damit sie im Dunkelmodus von
     allein mitwandern. */
  --u-hairline:        rgba(26, 29, 24, .15);
  --u-hairline-strong: rgba(26, 29, 24, .26);
  --u-sheen:           rgba(255, 255, 255, .55);

  /* ── Text ─────────────────────────────────────────────────────────── */
  --u-text:           #1a1d18;
  --u-text-2:         #545c4e;
  /* War #767e6b und damit 4,23:1 auf Weiss, 3,82 auf der Seite, 3,56 auf
     Canvas -- unter der Schwelle fuer Fliesstext, an 37 Stellen benutzt.
     Der neue Wert haelt 5,96 / 5,38 / 5,02 und bleibt mit Faktor 2,9 zum
     Fliesstext deutlich als gedaempft lesbar. Gedaempft heisst leiser,
     nicht unlesbar. */
  --u-text-muted:     #5f6657;
  --u-text-faint:     #7d8573;   /* Platzhalter */
  --u-text-on-inv:    rgba(220, 235, 210, .9);

  /* ── Marke ────────────────────────────────────────────────────────── */
  --u-brand:          #72b836;
  --u-brand-hover:    #5a9228;

  /* --u-brand-text ist die Rolle "Marke als TEXTfarbe" -- und der Grund,
     warum die Trennung von --u-brand ueberhaupt noetig ist:

       #72b836 auf Weiss    2,43:1     auf Seite 2,20:1   auf Canvas 2,05:1
       #437217 auf Weiss    5,74:1     auf Seite 5,18:1   auf Canvas 4,84:1

     Die Marke ist eine FLAECHE, kein Textton. Als Flaeche traegt sie weisse
     Schrift und ist richtig; als Textfarbe auf hellem Grund verfehlt sie AA
     um mehr als die Haelfte. Der Wert hier ist der HELLSTE Gruenton
     derselben Familie (Farbton 133,7 beibehalten, Saettigung mit der
     Helligkeit mitgefuehrt), der auf allen drei hellen Untergruenden 4,5:1
     erreicht -- mit etwas Reserve, damit ein spaeteres Nachjustieren der
     Flaechen ihn nicht wieder unter die Schwelle schiebt. */
  --u-brand-text:     #437217;

  --u-brand-wash:     rgba(114, 184, 54, .12);
  --u-brand-line:     rgba(114, 184, 54, .28);
  --u-brand-focus:    rgba(90, 146, 40, .32);   /* Fokusring, war --field-focus */

  /* ── Semantik ─────────────────────────────────────────────────────────
     Bewusst als Literale und NICHT ueber oklch abgeleitet: eine Warnfarbe
     hat eine kulturelle Identitaet ("das ist Rot"), die schwerer wiegt als
     mathematisch gleichmaessige Abstaende. Die Werte hier sind die heutigen
     Bootstrap-Toene; Olymp hat handgetunte, die die Kontrastpruefung
     bestehen. In Etappe 4 werden es dieselben in beiden Systemen. */
  --u-ok:     #4caf50;
  --u-warn:   #ff9800;
  --u-danger: #f44336;
  --u-info:   #2196f3;

  /* ── Abstand ──────────────────────────────────────────────────────────
     4er-Raster mit zwei Zwischenstufen. Noch ungenutzt; Komponenten wandern
     beim Anfassen darauf. Abgleich mit dem Bestand: .tw-pane 16px = s-6,
     .tw-desktop-main 20/24px = s-7/s-8. */
  --u-s-1: 2px;   --u-s-2: 4px;   --u-s-3: 6px;   --u-s-4: 8px;
  --u-s-5: 12px;  --u-s-6: 16px;  --u-s-7: 20px;  --u-s-8: 24px;
  --u-s-9: 28px;  --u-s-10: 32px; --u-s-11: 40px; --u-s-12: 48px;
  --u-s-13: 56px; --u-s-14: 64px;

  /* ── Typografie ───────────────────────────────────────────────────────
     Untergrenze ist 11px. Heute verletzen das 72 von 163 Groessenangaben in
     app.css, die kleinste liegt bei 8,4px. html{font-size:14px} bleibt
     unangetastet -- daran haengen 163 rem-Werte. Deshalb sind diese Tokens
     in px und werden komponentenweise eingesetzt. */
  --u-t-2xs: 11px; --u-t-xs: 12px; --u-t-sm: 13px; --u-t-md: 14px;
  --u-t-lg:  15px; --u-t-xl: 17px; --u-t-2xl: 20px; --u-t-3xl: 25px;
  --u-lh-tight: 1.3; --u-lh: 1.5; --u-lh-loose: 1.6;

  /* Gewichtsband. Bewusst nur zwei Stufen: die Schriftfamilie hier ist
     Segoe UI / system-ui, und 500 faellt dort unter Windows auf Regular
     zurueck. Olymp laedt variable Achsen und kann feiner abstufen. */
  --u-w-normal: 400;
  --u-w-strong: 600;

  --u-track-tight: -0.022em;   /* Display ab 20px auf HELL */
  --u-track-dark:   0.006em;   /* Fliesstext auf DUNKEL: helle Schrift blueht
                                  optisch auf und wirkt enger als sie ist */
  --u-track-caps:   0.08em;    /* Versalien-Label; heute sieben verschiedene
                                  Werte allein in app.css */

  /* ── Radien ───────────────────────────────────────────────────────────
     Gleiche Namen wie in Olymp, andere Werte. Radius ist Markencharakter:
     hier dichter, drueben weicher. */
  --u-r-xs: 4px; --u-r-sm: 6px; --u-r-md: 9px; --u-r-lg: 12px;
  --u-r-xl: 16px; --u-r-full: 999px;

  /* ── Elevation ────────────────────────────────────────────────────────
     Noch die heutigen Werte, damit diese Etappe nichts aendert. In Etappe 3
     wird daraus Tiefe aus Haarlinie plus Glanzkante statt aus Weichzeichner:
     16px Streuung mit 1px Kante liest als Objekt, 24px ohne Kante als Nebel. */
  --u-e-1: 0 1px 2px rgba(24, 34, 16, .05);
  --u-e-2: 0 1px 3px rgba(24, 34, 16, .07), 0 1px 2px rgba(24, 34, 16, .04);
  --u-e-3: 0 8px 24px rgba(24, 34, 16, .10);

  /* ── Bewegung ─────────────────────────────────────────────────────────
     Die Kurve ist die aus Olymp; sie ist gut, und damit aendert sich beim
     Angleichen dort nichts. */
  --u-dur-1: 90ms;  --u-dur-2: 150ms; --u-dur-3: 220ms; --u-dur-4: 320ms;
  --u-ease:      cubic-bezier(.22, .68, .18, 1);
  --u-ease-in:   cubic-bezier(.5, 0, .9, .4);
  --u-ease-play: cubic-bezier(.2, .9, .25, 1.02);

  /* ── z-Index ──────────────────────────────────────────────────────────
     Die Leiter ist NACH der bestehenden Ordnung gebaut, nicht umgekehrt.
     Heute stehen die Werte verstreut und teils absurd hoch: 1000, 1090,
     9999 (dreimal), 19000, 20000, 20050, 99999. Jede paarweise Beziehung
     darunter bleibt hier erhalten -- nachgeprueft --, nur die Zahlen werden
     klein und tragen einen Namen. Die einzige Aenderung ist ein Gleichstand,
     der heute per DOM-Reihenfolge entschieden wurde: Taskleiste gegen
     Dropdown, beide 9999. Ein Dropdown aus der Kopfleiste gehoert ueber die
     Taskleiste, also bekommt es die hoehere Stufe.

     Beim Aufraeumen aufgefallen: #toast-container traegt im Layout einen
     Inline-z-index (19999), der die CSS-Regel (1090) ueberstimmt -- die war
     seit jeher wirkungslos. Es gibt drei Toast-Wege im Haus (Bootstrap-Toasts,
     twToast, der Toast in der Ticket-Ansicht) auf drei verschiedenen Stufen.
     Sie liegen jetzt alle auf --u-z-toast; sie stehen ohnehin auf
     verschiedenen Hoehen am rechten unteren Rand und ueberlappen nicht.

     Die Fensterschicht bleibt bewusst ganz unten. Sie liegt geometrisch
     ohnehin zwischen Kopf- und Taskleiste (#tw-desktop hat overflow:hidden),
     und die Vollbild-Overlays muessen darueber bleiben koennen -- die kommen
     aus den Fenstern heraus, weil overflow:hidden position:fixed nicht
     klammert. */
  --u-z-sticky:      20;    /* Sticky-Kopf im Fensterinhalt */
  --u-z-window:     100;    /* Fenster; Band 100-400, siehe window-manager.js */
  --u-z-window-part: 200;   /* Griffe IM Fenster, eigener Stapelkontext */
  --u-z-nav:       1000;    /* Kopfleiste */
  --u-z-modal:     1050;    /* Bootstrap, fremdgesetzt -- nur dokumentiert */
  --u-z-dock:      1100;    /* Taskleiste */
  --u-z-menu:      1200;    /* Dropdowns, Popover, Schnellsuche */
  --u-z-overlay:   1300;    /* schwebende Widgets, z.B. Sysadmin-Chat */
  --u-z-toast:     1400;    /* alle drei Toast-Wege, siehe unten */
  --u-z-palette:   1500;    /* Spotlight, Hilfe */
  --u-z-fullscreen:1600;    /* Barcode-Scanner und Verwandte */
}

/* ═══════════════════════════════════════════════════════════════════════
   AUFSATZ — dieselben Rollen, aber aus den Reglern gerechnet.
   Warum getrennt und nicht gleich oben: ein Browser ohne oklch() speichert
   den Wert zwar klaglos (Custom Properties nehmen fast jeden Tokenstrom),
   aber beim Einsetzen in background oder color wird er ungueltig -- und ein
   var()-Rueckfall greift dann NICHT, der gilt nur bei fehlender Variable.
   Die Eigenschaft fiele also aus, nicht auf den Rueckfall zurueck. Mit dem
   Literal oben und dem Aufsatz hier ist die Datei auf jedem Browser exakt,
   und auf allen ab 2023 dreht der Regler.
   Gegengerechnet: 9 der 13 Rollen ergeben denselben sRGB-Wert wie oben,
   vier weichen um eine Einheit in einem Kanal ab.
   ═══════════════════════════════════════════════════════════════════════ */
@supports (color: oklch(50% 0.1 120)) and (color: color-mix(in oklab, red, blue)) {
  :root {
    --u-surface-2:       oklch(96.4% 0.0069 var(--u-h-neut));
    --u-surface-3:       oklch(94.1% 0.0127 var(--u-h-neut));
    --u-surface-alt:     oklch(97.6% 0.0069 var(--u-h-neut));
    --u-field-off:       oklch(97.0% 0.0069 var(--u-h-neut));
    --u-surface-inv-2:   oklch(23.9% 0.0182 var(--u-h-neut));
    --u-border:          oklch(90.8% 0.0173 var(--u-h-neut));
    --u-border-strong:   oklch(86.7% 0.0204 var(--u-h-neut));
    --u-text:            oklch(22.6% 0.0105 var(--u-h-neut));
    --u-text-2:          oklch(46.3% 0.0243 var(--u-h-neut));
    --u-text-muted:      oklch(50.0% 0.0248 var(--u-h-neut));
    --u-text-faint:      oklch(60.5% 0.0282 var(--u-h-neut));
    --u-brand:           oklch(71.1% 0.1756 var(--u-h-brand));
    --u-brand-hover:     oklch(59.9% 0.1484 var(--u-h-brand));
    --u-brand-text:      oklch(50.0% 0.1294 var(--u-h-brand));

    --u-hairline:        color-mix(in oklab, var(--u-text) 15%, transparent);
    --u-hairline-strong: color-mix(in oklab, var(--u-text) 26%, transparent);
    --u-sheen:           color-mix(in oklab, #ffffff 55%, transparent);
    --u-brand-wash:      color-mix(in srgb, var(--u-brand) 12%, transparent);
    --u-brand-line:      color-mix(in srgb, var(--u-brand) 28%, transparent);
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   BRUECKE — die alten Namen bleiben, sie zeigen nur woandershin.
   Nichts in app.css muss angefasst werden. Wer einen dieser Namen liest,
   liest ab hier den Vertrag.
   ═══════════════════════════════════════════════════════════════════════ */
:root {
  --bar-bg:            var(--u-surface-inv-2);
  --bar-hover:         var(--u-brand-wash);
  --bar-text:          var(--u-text-on-inv);
  --bar-border:        var(--u-line-on-inv);

  --accent:            var(--u-brand);
  --accent-dark:       var(--u-brand-hover);
  --accent-light:      var(--u-brand-wash);

  --desktop-bg:        var(--u-surface-inv);

  --bg-card:           var(--u-surface);
  --bg-body:           var(--u-surface-2);
  --canvas:            var(--u-surface-3);
  --panel-bg:          var(--u-surface-alt);

  --text-primary:      var(--u-text);
  --text-secondary:    var(--u-text-2);
  --text-muted:        var(--u-text-muted);
  --placeholder:       var(--u-text-faint);

  --success:           var(--u-ok);
  --warning:           var(--u-warn);
  --danger:            var(--u-danger);
  --info:              var(--u-info);

  --border:            var(--u-border);
  --border-strong:     var(--u-border-strong);
  --field-bg:          var(--u-surface);
  --field-disabled-bg: var(--u-field-off);
  --field-focus:       0 0 0 3px var(--u-brand-focus);

  --radius-sm:         var(--u-r-sm);
  --radius-md:         var(--u-r-md);
  --radius-lg:         var(--u-r-lg);

  --shadow-xs:         var(--u-e-1);
  --shadow-sm:         var(--u-e-2);
  --shadow-md:         var(--u-e-3);
}
