/* ================================================================
   hkdtlab.de — style.css
   Umsetzung von DESIGN.md, überarbeitete Fassung vom 14.09.2026.
   Technische Grundlagen aus _geruest/style.css übernommen,
   Gestaltung vollständig eigenständig.
   ================================================================ */


/* ================================================================
   1. Grundlagen  (aus _geruest/style.css, unverändert)
   ================================================================ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
}

img,
picture,
video,
svg {
  display: block;
  max-width: 100%;
}

input,
button,
textarea,
select {
  font: inherit;
}

/* Sichtbarer Tastaturfokus. Nie ohne gleichwertigen Ersatz entfernen. */
:focus-visible {
  outline: 3px solid;
  outline-offset: 2px;
}


/* ================================================================
   2. Schrift

   Space Grotesk, Regular, SIL Open Font License.
   Herkunft und Lizenz in fonts/LIZENZEN.md, Lizenztext in
   fonts/OFL.txt — letztere wird mitdeployt, weil die OFL verlangt,
   dass sie jeder Kopie der Schriftdatei beiliegt.
   ================================================================ */

@font-face {
  font-family: "Space Grotesk";
  src: url("fonts/space-grotesk-v22-latin-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}


/* ================================================================
   3. Registrierte Eigenschaften

   @property ist die Voraussetzung dafür, dass die Positionen
   überhaupt animierbar sind — ohne Registrierung behandelt der
   Browser sie als Zeichenketten und interpoliert nicht.

   Prozent statt vmax (DESIGN.md 7): background-position rechnet
   Prozent gegen die Fläche abzüglich der Formgröße. Die Kreise
   verteilen sich dadurch im Hoch- wie im Querformat von selbst,
   statt in vmax gerechnet im Hochformat im oberen Drittel
   hängenzubleiben. Die Größen bleiben vmax.

   Die Ausgangswerte stehen in Abschnitt 5 — sie sind zugleich die
   stehende Komposition für prefers-reduced-motion.
   ================================================================ */

@property --a-x { syntax: "<percentage>"; inherits: false; initial-value: 50%; }
@property --a-y { syntax: "<percentage>"; inherits: false; initial-value: 50%; }
@property --b-x { syntax: "<percentage>"; inherits: false; initial-value: 50%; }
@property --b-y { syntax: "<percentage>"; inherits: false; initial-value: 50%; }
@property --c-x { syntax: "<percentage>"; inherits: false; initial-value: 50%; }
@property --c-y { syntax: "<percentage>"; inherits: false; initial-value: 50%; }


/* ================================================================
   4. Farbe

   Werte aus DESIGN.md 5. Zwei gedeckte Töne und ein gesättigter:
   der Magenta ist der Ausreißer und wirkt über Sättigung, nicht
   über Helligkeit — er ist der dunkelste der drei Kreise.

   Gemessen gegen die Grundfläche:
     Lavendel   9,0:1     Sättigung 0,49
     Mint      12,2:1     Sättigung 0,48
     Magenta    5,8:1     Sättigung 1,00
   ================================================================ */

:root {
  --grund: #0d0a1a;
  --lavendel: 179 164 224;  /* #b3a4e0 */
  --mint: 143 216 192;      /* #8fd8c0 */
  --magenta: 255 45 149;    /* #ff2d95 */
  --schrift: "Space Grotesk", system-ui, sans-serif;
}

html {
  background-color: var(--grund);
}


/* ================================================================
   5. Die Fläche  (index.html)

   Vier Hintergrundebenen auf einem einzigen Element. Keine
   Formelemente im DOM.

   Reihenfolge von oben nach unten:
     1  Abdunklung unten links      normal
     2  Kreis C, Magenta            screen
     3  Kreis B, Mint               screen
     4  Kreis A, Lavendel           screen
     -  Grundfläche #0d0a1a

   Die Kreisränder laufen weich aus (DESIGN.md 8: keine sichtbaren
   Konturen). Die Zielfarbe des Verlaufs ist derselbe Ton mit
   Alpha 0 statt `transparent` — sonst interpolieren manche
   Browser über Schwarz und erzeugen einen grauen Saum.
   ================================================================ */

body.flaeche {
  block-size: 100vh;
  block-size: 100svh;
  overflow: hidden;
  overscroll-behavior: none;

  display: flex;
  align-items: flex-end;

  background-color: var(--grund);

  /* Radien der Abdunklung. Mobil kleiner, weil der Randabstand dort
     nur 1.5rem beträgt und die Schrift entsprechend näher an der
     Ecke sitzt. Rechnung in Abschnitt 6. */
  --dunkel-x: 20rem;
  --dunkel-y: 11rem;

  background-image:
    /* 1 — Abdunklung, siehe Abschnitt 6 */
    radial-gradient(var(--dunkel-x) var(--dunkel-y) at 0% 100%,
      rgb(13 10 26 / 0.8) 0%,
      rgb(13 10 26 / 0.8) 60%,
      rgb(13 10 26 / 0) 100%),
    /* 2 — Magenta */
    radial-gradient(circle closest-side,
      rgb(var(--magenta)) 0%,
      rgb(var(--magenta) / 0.55) 45%,
      rgb(var(--magenta) / 0) 100%),
    /* 3 — Mint */
    radial-gradient(circle closest-side,
      rgb(var(--mint)) 0%,
      rgb(var(--mint) / 0.55) 45%,
      rgb(var(--mint) / 0) 100%),
    /* 4 — Lavendel */
    radial-gradient(circle closest-side,
      rgb(var(--lavendel)) 0%,
      rgb(var(--lavendel) / 0.55) 45%,
      rgb(var(--lavendel) / 0) 100%);

  background-size:
    100% 100%,
    44vmax 44vmax,
    64vmax 64vmax,
    52vmax 52vmax;

  background-repeat: no-repeat;

  background-blend-mode: normal, screen, screen, screen;

  /* Ausgangswerte. Ohne Animation — sei es reduced-motion oder ein
     Browser ohne @property — ist das die stehende Komposition:
     Lavendel oben links, Mint oben rechts, Magenta unten Mitte. */
  --a-x: 22%;
  --a-y: 24%;
  --b-x: 76%;
  --b-y: 34%;
  --c-x: 46%;
  --c-y: 72%;

  background-position:
    0 0,
    var(--c-x) var(--c-y),
    var(--b-x) var(--b-y),
    var(--a-x) var(--a-y);

  animation:
    a-x 53s ease-in-out infinite alternate,
    a-y 59s ease-in-out infinite alternate,
    b-x 61s ease-in-out infinite alternate,
    b-y 71s ease-in-out infinite alternate,
    c-x 73s ease-in-out infinite alternate,
    c-y 83s ease-in-out infinite alternate;
}

/* Die Keyframes nennen nur das Ziel, der Ausgangswert kommt aus der
   Regel oben. Die Dauern sind Primzahlen zwischen 53 s und 83 s,
   also paarweise teilerfremd. Weil x und y je Kreis verschieden
   schnell laufen, entsteht eine Lissajous-Figur und keine
   Umlaufbahn.

   Mit alternate ist eine Dauer der halbe Weg: die vollen Perioden
   liegen bei 106 s bis 166 s und damit in der Tempo-Spanne aus
   DESIGN.md 7.

   Schnellste Bewegung im Querformat 1920x1080: 12,6 px/s in der
   Spitze, also rund 25 px in zwei Sekunden — bei einer konturlosen
   Form von rund 1000 px Durchmesser. */

@keyframes a-x { to { --a-x: 68%; } }
@keyframes a-y { to { --a-y: 78%; } }
@keyframes b-x { to { --b-x: 28%; } }
@keyframes b-y { to { --b-y: 82%; } }
@keyframes c-x { to { --c-x: 82%; } }
@keyframes c-y { to { --c-y: 20%; } }


/* ================================================================
   6. Kontrast des Schriftzugs

   Der Schriftzug steht fest in Weiß und kehrt sich nicht um
   (DESIGN.md 5).

   Der hellste erreichbare Punkt der Fläche ist die Überlagerung
   aller drei Kreise: #fff4fc. Weiß erreicht dort 1,07:1. Deshalb
   liegt über dem Kreis-Stack eine Ebene in Grundflächenfarbe mit
   Deckkraft 0.80, weich auslaufend, Zentrum in der Ecke unten
   links:

     #fff4fc unter 0.80 Grundfläche  ->  #3d3947  ->  Weiss 11,2:1

   Das Minimum für 4,5:1 läge bei Deckkraft 0,55. Die 0,80 sind
   bewusster Abstand.

   Diese Zusage gilt unabhängig davon, wo die Kreise gerade stehen —
   anders als eine Beschränkung der Kreisbahnen, die über alle
   Lissajous-Phasen halten müsste und nur stichprobenhaft prüfbar
   wäre. Wer die Deckkraft senkt oder das Plateau verkleinert,
   bricht die Kontrastzusage: beides oben in Ebene 1.

   Damit die 11,2:1 überall unter der Schrift gelten, muss sie
   vollständig im Plateau liegen — also innerhalb von 60 % der
   Radien. Geprüft wird die von der Ecke am weitesten entfernte
   Textecke, mit Reserve für die tatsächliche Laufweite:

     mobil, Randabstand 1.5rem = 24 px
       Schrift reicht bis rund  144 x  52 px ab der Ecke
       Plateau 60 % von 20rem x 11rem =  192 x 106 px
       (144/192)^2 + (52/106)^2 = 0,80  < 1   liegt drin

     ab 40em, Randabstand bis 4rem = 64 px
       Schrift reicht bis rund  200 x 100 px ab der Ecke
       Plateau 60 % von 30rem x 16rem =  288 x 154 px
       (200/288)^2 + (100/154)^2 = 0,90  < 1  liegt drin

   Wird der Randabstand erhöht oder die Schrift vergrößert, ist
   diese Rechnung zu wiederholen.
   ================================================================ */

.flaeche main {
  padding: 1.5rem;
}

/* DESIGN.md 4 setzt den Randabstand mobil auf 1.5rem und darüber
   auf clamp(2rem, 4vmin, 4rem). Die Abdunklung wächst mit, sonst
   verließe die Schrift das Plateau. */
@media (min-width: 40em) {
  .flaeche main {
    padding: clamp(2rem, 4vmin, 4rem);
  }

  body.flaeche {
    --dunkel-x: 30rem;
    --dunkel-y: 16rem;
  }
}

.flaeche h1 {
  margin: 0;
  font: 400 1rem/1 var(--schrift);
  letter-spacing: 0.3em;
  color: #fff;
}

/* Dauerhaft unterstrichen, nicht erst bei Hover: Der Schriftzug ist
   der einzige Weg zur Datenschutzerklärung, und auf Touch-Geräten
   gibt es kein Hover. Durch den weiten Abstand und die geringe
   Stärke liest sich der Strich bei der Laufweite von 0.3em eher als
   Grundlinie denn als Linkauszeichnung. */
.flaeche h1 a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.75em;
}

.flaeche h1 a:hover,
.flaeche h1 a:focus-visible {
  text-decoration-thickness: 2px;
}


/* ================================================================
   7. Textseiten  (datenschutz.html)

   Kein zweites Gestaltungssystem: dieselbe Grundfläche, dieselbe
   Schrift, dieselbe Laufweite in den Überschriften, derselbe
   Randabstand. Was fehlt, sind die Kreise und die Bewegung — die
   Fläche bleibt der Startseite vorbehalten.

   Die Zugehörigkeit trägt der Fließtext: #ddd8ea statt neutralem
   Grau, also leicht in Richtung des Lavendeltons gezogen. Das
   verbindet mit der Palette, ohne einen Akzent zu setzen.

   Kontraste gegen #0d0a1a, nachgerechnet:
     Fließtext          #ddd8ea   14,0:1
     Überschriften      #ffffff   19,5:1
     gedämpft, Marker   #a79fbe    7,8:1
     und Stand-Angabe

   Das gedämpfte Grau liegt bewusst über 4,5:1 — es trägt mit der
   Stand-Angabe echten Inhalt und ist kein Dekorationston.
   ================================================================ */

body.seite-text {
  /* Zeilenlänge unter 75 Zeichen. Space Grotesk ist proportional,
     dort entspricht 1ch (Breite der Ziffer 0) mehr als einem
     durchschnittlichen Zeichen — 62ch träfe die Grenze nicht
     zuverlässig. min() nimmt die jeweils strengere Schranke, egal
     wie breit die Ziffer der Schrift ausfällt. */
  max-inline-size: min(52ch, 32em);

  padding: 1.5rem;
  background-color: var(--grund);
  color: #ddd8ea;
  font: 400 1rem/1.7 var(--schrift);
}

/* Derselbe Umschaltpunkt und dieselbe Rampe wie auf der Fläche. */
@media (min-width: 40em) {
  body.seite-text {
    padding: clamp(2rem, 4vmin, 4rem);
  }
}

/* Der Rücklink nimmt die Setzung des Schriftzugs auf: gleiche
   Größe, gleiche Laufweite, gleicher Unterstrichabstand. */
.seite-text header {
  margin-block-end: clamp(2.5rem, 8vmin, 5rem);
}

.seite-text header a {
  color: #fff;
  font-size: 1rem;
  letter-spacing: 0.3em;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.75em;
}

.seite-text h1 {
  margin: 0 0 2.5rem;
  font-size: 1.375rem;
  font-weight: 400;
  letter-spacing: 0.2em;
  line-height: 1.3;
  color: #fff;
}

.seite-text h2 {
  margin: 2.5rem 0 0.5rem;
  font-size: 1rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  color: #fff;
}

.seite-text p {
  margin: 0 0 1rem;
  overflow-wrap: break-word;
}

.seite-text ul {
  margin: 0 0 1rem;
  padding-inline-start: 1.4em;
}

.seite-text li {
  margin-block-end: 0.35rem;
}

.seite-text li::marker {
  color: #a79fbe;
}

/* Die letzte Zeile ist die Stand-Angabe. */
.seite-text main > p:last-child {
  margin-block-start: 2.5rem;
  color: #a79fbe;
}

/* Im Fließtext müssen Links erkennbar sein, deshalb hier
   durchgehend unterstrichen — mit kleinerem Abstand als auf der
   Fläche, sonst kollidiert der Strich mit der nächsten Zeile. */
.seite-text a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

.seite-text a:hover,
.seite-text a:focus-visible {
  text-decoration-thickness: 2px;
}


/* ================================================================
   8. Bewegungsreduktion

   DESIGN.md 7 verlangt Einfrieren, nicht Beschleunigen. Die Regel
   aus dem Gerüst würde die Animationen auf 0,01 ms stauchen und
   erst danach zurücksetzen; hier werden sie stattdessen gar nicht
   erst gestartet. Es bleibt die Komposition aus Abschnitt 5.
   ================================================================ */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}


/* ================================================================
   9. Druck
   ================================================================ */

@media print {
  *,
  *::before,
  *::after {
    background: transparent !important;
    color: #000 !important;
    box-shadow: none !important;
  }

  .flaeche {
    block-size: auto !important;
    overflow: visible !important;
  }

  a[href]::after {
    content: " (" attr(href) ")";
  }

  a[href^="#"]::after {
    content: "";
  }
}
