/* ==========================================================================
   louis-fritz.com

   Aufbau der Seite: dunkler Kopfblock, heller Mittelteil, dunkler
   Kontaktblock. Die dunklen Baender sind IMMER dunkel, auch im hellen
   Systemmodus. Deshalb haben sie eigene feste Farben (--dk-*), die nicht
   vom Systemmodus abhaengen.

   Keine externen Schriften und kein CDN, weil Schulnetze das oft sperren.
   Serif fuer Ueberschriften kommt aus dem System.
   ========================================================================== */

:root {
  /* ---- Heller Mittelteil ---- */
  --bg:        #f7f5f1;
  --bg-tint-a: rgba(43, 93, 139, 0.09);
  --bg-tint-b: rgba(196, 148, 84, 0.08);
  --card:      #fffefc;
  --card-2:    #fbf9f5;

  --ink:    #191c22;
  --ink-2:  #545a66;
  --ink-3:  #69707b;

  --line:     #e3dfd7;
  --line-2:   #efece5;
  --accent:   #2b5d8b;
  --accent-d: #1d4467;
  --accent-soft: rgba(43, 93, 139, 0.10);

  /* ---- Palette. Jedes Projekt und jeder Schritt im Zeitstrahl bekommt
          eine davon, ueber die Variable --pc am Element. Gruen und Orange
          sind an die echten Farben von Fintro und StartupVisit angelehnt,
          damit Karte und verlinkte Seite zusammenpassen. ---- */
  --c-blau:    #2b6cab;
  --c-gruen:   #2c7d5c;
  --c-violett: #6a4bb0;
  --c-orange:  #ab5411;
  --c-blau-soft:    rgba(43, 108, 171, 0.11);
  --c-gruen-soft:   rgba(44, 125, 92, 0.11);
  --c-orange-soft:  rgba(194, 95, 20, 0.11);
  --c-violett-soft: rgba(106, 75, 176, 0.11);

  --punkt: rgba(25, 28, 34, 0.055);   /* Raster im Hintergrund */

  --sh-1: 0 1px 2px rgba(25, 28, 34, 0.04), 0 4px 14px rgba(25, 28, 34, 0.05);
  --sh-2: 0 2px 4px rgba(25, 28, 34, 0.05), 0 14px 34px rgba(25, 28, 34, 0.09);

  /* ---- Dunkle Baender, in beiden Systemmodi gleich ---- */
  --dk-bg:   #0e1116;
  --dk-bg-2: #141922;
  --dk-ink:  #f4f1ec;
  --dk-ink2: #a9b3c0;
  --dk-ink3: #79839190;
  --dk-line: rgba(255, 255, 255, 0.13);
  --dk-acc:  #8fbde6;

  /* ---- Schrift ---- */
  --serif: ui-serif, "New York", Georgia, "Iowan Old Style", "Times New Roman", serif;
  --sans:  -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
           "Helvetica Neue", Arial, sans-serif;

  /* ---- Raster ---- */
  --wrap: 74rem;
  --text: 42rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:        #171a20;
    --bg-tint-a: rgba(125, 179, 221, 0.08);
    --bg-tint-b: rgba(196, 148, 84, 0.06);
    --card:      #1e222a;
    --card-2:    #1a1e25;

    --ink:    #eae7e1;
    --ink-2:  #a6acb8;
    --ink-3:  #7c8494;

    --line:   #2e343d;
    --line-2: #262b33;
    --accent: #8ab9e0;
    --accent-d: #a9cdec;
    --accent-soft: rgba(138, 185, 224, 0.14);

    --c-blau:    #6ea8de;
    --c-gruen:   #5cb98d;
    --c-violett: #a186e0;
    --c-orange:  #e8954a;
    --c-blau-soft:    rgba(110, 168, 222, 0.15);
    --c-gruen-soft:   rgba(92, 185, 141, 0.15);
    --c-orange-soft:  rgba(232, 149, 74, 0.15);
    --c-violett-soft: rgba(161, 134, 224, 0.15);

    --punkt: rgba(255, 255, 255, 0.05);

    --sh-1: 0 1px 2px rgba(0, 0, 0, 0.30), 0 4px 14px rgba(0, 0, 0, 0.24);
    --sh-2: 0 2px 4px rgba(0, 0, 0, 0.34), 0 14px 34px rgba(0, 0, 0, 0.40);
  }
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background-color: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

/* Hinter der ganzen Seite: zwei weiche Farbfelder plus ein sehr feines
   Punktraster, das den hellen Mittelteil mit dem Punktraster im Kopfblock
   verbindet. Ohne beides wirkt die helle Flaeche leer. Haengt an body, nicht
   an main: main ist auf den Rechtsseiten nur textbreit, dort saehe der
   Schimmer wie ein Kasten aus. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(circle at 1px 1px, var(--punkt) 1px, transparent 0),
    radial-gradient(52rem 34rem at 8% 12%,  var(--bg-tint-a), transparent 68%),
    radial-gradient(46rem 30rem at 96% 82%, var(--bg-tint-b), transparent 70%);
  background-size: 26px 26px, auto, auto;
}

/* Feine Koernung ueber der ganzen Seite. Nimmt grossen Farbflaechen das
   Sterile. Sehr schwach dosiert, damit Text scharf bleibt, und ohne
   Mausereignisse, damit nichts unklickbar wird. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 60;
  pointer-events: none;
  opacity: 0.038;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

img { max-width: 100%; height: auto; display: block; }

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-d); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 3px;
}

.skip { position: absolute; left: -9999px; }
.skip:focus {
  left: 1rem; top: 1rem;
  z-index: 50;
  padding: 0.6rem 1rem;
  background-color: var(--card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 8px;
}

/* ==========================================================================
   Baender
   ========================================================================== */

.band { position: relative; }

.band-top {
  background-color: var(--dk-bg);
  color: var(--dk-ink);
  overflow: hidden;
  isolation: isolate;
}

#fx {
  position: absolute;
  inset: 0;
  z-index: -2;
  display: block;
}

/* ---------- Driftende Farbwolken ----------
   Wichtig: nur transform wird animiert. Dann muss der Browser die
   weichgezeichnete Flaeche einmal berechnen und danach nur verschieben.
   Wuerde man Groesse, Farbe oder Deckkraft animieren, waere jedes Bild
   eine neue Weichzeichnung und es ruckelt. */

.blobs {
  position: absolute;
  inset: -15%;
  z-index: -3;
  overflow: hidden;
  pointer-events: none;
}

.blob {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(95px);
  opacity: 0.34;
  mix-blend-mode: screen;
  will-change: transform;
}

/* Groessen an die Fensterbreite gekoppelt. Mit festen rem-Werten fuellte
   eine Wolke ein schmales Fenster fast allein aus, dann war der Kopf zu
   bunt und der Text verlor Kontrast. */
.blob-1 {
  width: min(40rem, 62vw); height: min(40rem, 62vw);
  top: -8%; left: -8%;
  background: #2f6fd0;
  animation: drift-1 38s ease-in-out infinite;
}
.blob-2 {
  width: min(34rem, 54vw); height: min(34rem, 54vw);
  top: 26%; right: -10%;
  background: #7b4fd6;
  animation: drift-2 46s ease-in-out infinite;
}
.blob-3 {
  width: min(30rem, 48vw); height: min(30rem, 48vw);
  bottom: -12%; left: 34%;
  background: #c2801f;
  opacity: 0.2;
  animation: drift-3 52s ease-in-out infinite;
}

/* Im schmalen Fenster liegen die Wolken naeher am Text, also blasser */
@media (max-width: 62rem) {
  .blob   { opacity: 0.26; }
  .blob-3 { opacity: 0.16; }
}

@keyframes drift-1 {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  33%      { transform: translate3d(14vw, 6vh, 0) scale(1.16); }
  66%      { transform: translate3d(5vw, 14vh, 0) scale(0.92); }
}
@keyframes drift-2 {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  40%      { transform: translate3d(-12vw, 10vh, 0) scale(1.2); }
  70%      { transform: translate3d(-4vw, -8vh, 0) scale(0.95); }
}
@keyframes drift-3 {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(10vw, -12vh, 0) scale(1.25); }
}

@media (prefers-reduced-motion: reduce) {
  .blob { animation: none; }
}

.band-contact {
  background-color: var(--dk-bg);
  color: var(--dk-ink);
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.band-contact::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(42rem 26rem at 18% 120%,
              rgba(90, 148, 202, 0.18), transparent 68%);
}

/* ==========================================================================
   Kopf
   ========================================================================== */

.top {
  position: relative;
  z-index: 2;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 1.6rem 1.5rem 0;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
}

.wordmark {
  font-family: var(--serif);
  font-size: 1.0625rem;
  letter-spacing: 0.01em;
  color: var(--ink);
}
.wordmark:hover { color: var(--ink); }

.top-right { display: flex; align-items: center; gap: 1.5rem; }

.nav { display: flex; gap: 1.5rem; font-size: 0.9375rem; }
.nav a { color: var(--ink-2); }
.nav a:hover { color: var(--accent); }

/* Kopf auf dunklem Grund */
.band-top .wordmark,
.band-top .wordmark:hover { color: var(--dk-ink); }
.band-top .nav a { color: var(--dk-ink2); }
.band-top .nav a:hover { color: var(--dk-ink); }
.band-top :focus-visible { outline-color: var(--dk-acc); }

/* ---------- Sprachumschalter ---------- */

.langswitch {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  background-color: var(--card);
}
.langswitch button {
  appearance: none;
  border: 0;
  margin: 0;
  padding: 0.3rem 0.55rem;
  background: transparent;
  color: var(--ink-3);
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  cursor: pointer;
  transition: background 0.14s ease, color 0.14s ease;
}
.langswitch button + button { border-left: 1px solid var(--line); }
.langswitch button:hover { color: var(--ink); }
.langswitch button.is-on { background-color: var(--accent); color: #fff; }
@media (prefers-color-scheme: dark) {
  .langswitch button.is-on { color: #10141a; }
}

.band-top .langswitch {
  background: rgba(255, 255, 255, 0.05);
  border-color: var(--dk-line);
}
.band-top .langswitch button { color: var(--dk-ink2); }
.band-top .langswitch button + button { border-left-color: var(--dk-line); }
.band-top .langswitch button:hover { color: var(--dk-ink); }
.band-top .langswitch button.is-on {
  background-color: var(--dk-acc);
  color: #0e1116;
}

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  position: relative;
  z-index: 2;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 5.5rem 1.5rem 5rem;
  min-height: min(84vh, 46rem);
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 4.5rem;
  align-items: center;
}

.eyebrow {
  margin: 0 0 1.25rem;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dk-ink2);
}

h1 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(3.25rem, 8.5vw, 6.25rem);
  line-height: 0.94;
  letter-spacing: -0.035em;
  margin: 0 0 1.75rem;
  color: var(--dk-ink);
}

/* Zweite Zeile des Namens als Farbverlauf. Faellt ohne
   background-clip auf die normale helle Schriftfarbe zurueck. */
.h1-grad {
  background: linear-gradient(100deg, #cfe0f2 0%, #a9bfe8 55%, #b3a6e0 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
@supports not ((background-clip: text) or (-webkit-background-clip: text)) {
  .h1-grad { background: none; color: var(--dk-ink); -webkit-text-fill-color: currentColor; }
}

.lead {
  margin: 0 0 1.75rem;
  max-width: 32rem;
  font-size: 1.1875rem;
  line-height: 1.6;
  color: var(--dk-ink2);
}

.motto {
  margin: 0 0 2.25rem;
  padding-left: 1.1rem;
  border-left: 2px solid var(--dk-acc);
  font-family: var(--serif);
  font-size: 1.125rem;
  font-style: italic;
  color: var(--dk-ink);
}

.hero-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; }

/* Die Verschiebung laeuft ueber --mx/--my, damit der Zeiger-Magnet in
   hero.js und der Anheb-Effekt beim Zeigen sich nicht gegenseitig
   ueberschreiben. Ohne JavaScript sind beide Variablen null. */
.btn {
  display: inline-block;
  padding: 0.75rem 1.4rem;
  border-radius: 10px;
  background-color: var(--dk-acc);
  color: #0e1116;
  font-size: 0.9375rem;
  font-weight: 600;
  border: 1px solid var(--dk-acc);
  transform: translate(var(--mx, 0px), calc(var(--my, 0px) + var(--lift, 0px)));
  transition: transform 0.18s ease-out, box-shadow 0.16s ease,
              background 0.14s ease, filter 0.14s ease;
}
.btn:hover {
  color: #0e1116;
  filter: brightness(1.08);
  --lift: -2px;
  box-shadow: 0 12px 28px rgba(143, 189, 230, 0.24);
}

.btn-ghost {
  background: transparent;
  color: var(--dk-ink);
  border-color: var(--dk-line);
  box-shadow: none;
}
.btn-ghost:hover {
  background: rgba(255, 255, 255, 0.07);
  color: var(--dk-ink);
  border-color: rgba(255, 255, 255, 0.3);
  filter: none;
  box-shadow: none;
}

.hero-photo { position: relative; }
.hero-photo img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  object-position: center 28%;
  border-radius: 16px;
  border: 1px solid var(--dk-line);
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.45);
}

/* ---------- Hinweis zum Weiterscrollen ---------- */

.scrollcue {
  position: relative;
  z-index: 2;
  display: block;
  width: 1px;
  height: 3.5rem;
  margin: 0 auto;
  padding-bottom: 2.5rem;
}
.scrollcue-line {
  display: block;
  width: 1px;
  height: 100%;
  background: linear-gradient(to bottom, transparent, var(--dk-acc));
  opacity: 0.55;
  transform-origin: top;
  animation: cue 2.6s ease-in-out infinite;
}
@keyframes cue {
  0%, 100% { transform: scaleY(0.35); opacity: 0.25; }
  50%      { transform: scaleY(1);    opacity: 0.65; }
}
@media (prefers-reduced-motion: reduce) {
  .scrollcue-line { animation: none; transform: scaleY(1); }
}

/* ==========================================================================
   Heller Mittelteil
   ========================================================================== */

.section {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 5rem 1.5rem;
}
/* Trennlinie zwischen Abschnitten laeuft an beiden Enden aus, statt hart
   von Rand zu Rand zu gehen. */
.section { position: relative; }
.section + .section::before {
  content: "";
  position: absolute;
  top: 0;
  left: 1.5rem;
  right: 1.5rem;
  height: 1px;
  background-image: linear-gradient(to right,
                    transparent, var(--line), transparent);
}
.section-flush::before { display: none; }

.section-head { margin-bottom: 2.75rem; }

/* Abschnitte durchnummerieren, 01 bis 04. Der Zaehler haengt am body,
   weil der Kontaktblock ausserhalb von main liegt. */
body { counter-reset: abschnitt; }

.section-head h2::before {
  counter-increment: abschnitt;
  content: counter(abschnitt, decimal-leading-zero);
  display: block;
  margin-bottom: 0.7rem;
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  color: var(--ink-3);
}
.band-contact .section-head h2::before { color: var(--dk-ink3); }

h2 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(2rem, 4.2vw, 2.75rem);
  line-height: 1.05;
  letter-spacing: -0.025em;
  margin: 0 0 0.85rem;
}

.section-sub {
  margin: 0;
  max-width: var(--text);
  color: var(--ink-2);
}

/* ==========================================================================
   Projekte
   ========================================================================== */

.projects {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.5rem;
  counter-reset: p;
}

.project {
  position: relative;
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr) minmax(0, 21rem);
  gap: 0 2rem;
  align-items: start;
  padding: 2rem 2rem 1.75rem;
  background-color: var(--card);
  /* Leichte Tönung in der Projektfarbe. Ohne die waren die Karten fast
     komplett weiss und wirkten leer. background-image, nicht die Kurzform
     background: sonst ueberschreibt es die Farbe darunter. */
  background-image:
    linear-gradient(133deg, var(--pc-soft, transparent) 0%, transparent 52%);
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: var(--sh-1);
  overflow: hidden;
  transition: transform 0.18s ease, box-shadow 0.18s ease,
              border-color 0.18s ease;
}

/* Farbige Kante links. Immer sichtbar, beim Zeigen kraeftiger. Die Farbe
   kommt aus --pc, das jede Karte im HTML selbst setzt. */
.project::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background-color: var(--pc, var(--accent));
  opacity: 0.4;
  transition: opacity 0.25s ease;
}
.project:hover {
  transform: translateY(-3px);
  box-shadow: var(--sh-2);
  border-color: var(--pc-soft, var(--accent-soft));
}
.project:hover::before { opacity: 1; }

/* ---------- Vorschaubild ----------
   Echte Aufnahme der verlinkten Seite. Nur der obere Teil, leicht
   angeschnitten und gekippt, damit es wie ein Fenster wirkt und nicht
   wie ein eingeklebtes Rechteck. */

.project-shot {
  display: block;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: 0 8px 24px rgba(25, 28, 34, 0.10);
  transform: perspective(900px) rotateY(-4deg) translateZ(0);
  transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1),
              box-shadow 0.35s ease;
}
.project-shot img {
  width: 100%;
  aspect-ratio: 16 / 11;
  object-fit: cover;
  object-position: top center;
}
.project:hover .project-shot {
  transform: perspective(900px) rotateY(0deg) translateY(-2px);
  box-shadow: 0 14px 34px rgba(25, 28, 34, 0.16);
}
@media (prefers-reduced-motion: reduce) {
  .project-shot,
  .project:hover .project-shot { transform: none; transition: none; }
}

.project-no {
  font-family: var(--serif);
  font-size: 2.5rem;
  line-height: 1;
  color: var(--pc, var(--ink-3));
  opacity: 0.4;
  font-variant-numeric: tabular-nums;
  user-select: none;
  transition: opacity 0.25s ease;
}
.project:hover .project-no { opacity: 0.85; }

.project-meta {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.9rem;
}

.tag {
  padding: 0.2rem 0.62rem;
  border-radius: 999px;
  background-color: var(--card-2);
  border: 1px solid var(--line);
  font-size: 0.75rem;
  letter-spacing: 0.03em;
  color: var(--ink-2);
}
.tag-main {
  background-color: var(--pc-soft, var(--accent-soft));
  border-color: transparent;
  color: var(--pc, var(--accent-d));
  font-weight: 600;
}

.year { font-size: 0.8125rem; color: var(--ink-3); }

.project h3 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 0.7rem;
}
.project h3 a { color: var(--ink); }
.project h3 a:hover { color: var(--accent); }

.project p {
  margin: 0 0 0.9rem;
  max-width: var(--text);
  color: var(--ink-2);
}

.project-why {
  padding-left: 0.95rem;
  border-left: 2px solid var(--line);
  font-size: 0.9375rem;
}

.project-links {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 1rem;
  margin: 1.1rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--line-2);
  font-size: 0.9375rem;
}

.link-out {
  font-weight: 600;
  color: var(--pc, var(--accent));
}
.link-out:hover { filter: brightness(0.88); }
.link-out::after {
  content: " \2197";
  display: inline-block;
  transition: transform 0.16s ease;
}
.link-out:hover::after { transform: translate(2px, -2px); }

.role { color: var(--ink-3); font-size: 0.875rem; }

/* ==========================================================================
   Zeitstrahl

   Die Linie links zeichnet sich mit dem Scrollen. hero.js setzt dazu die
   Hoehe von .tl-fill in Prozent und haengt .is-lit an die Schritte, die
   die Linie erreicht hat. Ohne JavaScript ist die Linie voll und alle
   Punkte sind farbig, dann fehlt nur die Bewegung.
   ========================================================================== */

/* Einzug und Linienposition stehen als Variablen, damit der Punkt sich
   daraus berechnen kann. Vorher waren beide Werte einzeln eingetragen und
   der Punkt sass ein paar Pixel neben der Linie. */
.timeline {
  --tl-pad:  3.25rem;   /* Einzug des Textes            */
  --tl-line: 0.5rem;    /* Abstand der Linie vom Rand    */
  --tl-dot:  11px;      /* Durchmesser des Punktes       */

  position: relative;
  list-style: none;
  margin: 0;
  padding: 0.4rem 0 0 var(--tl-pad);
  /* Karten nicht ueber die volle Seitenbreite ziehen: der Text darin ist
     schmaler, sonst steht rechts eine leere Flaeche. */
  max-width: 54rem;
}

.tl-rail {
  position: absolute;
  left: var(--tl-line);
  top: 1rem;
  bottom: 3.5rem;
  width: 2px;
  background-color: var(--line);
  border-radius: 2px;
  overflow: hidden;
}
.tl-fill {
  display: block;
  position: relative;
  width: 100%;
  height: 100%;
  background: linear-gradient(to bottom,
              var(--c-blau), var(--c-violett) 42%,
              var(--c-gruen) 74%, var(--c-orange));
}
.js .tl-fill { height: 0; }

/* Leuchtender Kopf an der Spitze der Linie. Wandert mit dem Scrollen mit,
   weil er am unteren Ende der gefuellten Linie haengt. */
.js .tl-fill::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -2px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  transform: translateX(-50%);
  background-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft), 0 0 12px 1px var(--accent);
}

/* ---------- Ein Schritt als Karte ---------- */

.tl-item {
  position: relative;
  margin-bottom: 1.1rem;
  padding: 1.4rem 1.6rem 1.35rem;
  background-color: var(--card);
  background-image:
    linear-gradient(133deg, var(--pc-soft, transparent) 0%, transparent 58%);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--sh-1);
  transition: transform 0.18s ease, box-shadow 0.18s ease,
              border-color 0.18s ease;
}
.tl-item:last-child { margin-bottom: 0; }
.tl-item:hover {
  transform: translateY(-2px);
  box-shadow: var(--sh-2);
  border-color: var(--pc-soft, var(--line));
}
@media (prefers-reduced-motion: reduce) {
  .tl-item:hover { transform: none; }
}

/* Feiner Steg von der Linie zur Karte. Laenge aus denselben Variablen
   berechnet wie der Punkt, damit beide zusammen bleiben. */
.tl-item::before {
  content: "";
  position: absolute;
  top: 1.6rem;
  left: calc(var(--tl-line) + 1px - var(--tl-pad));
  width: calc(var(--tl-pad) - var(--tl-line) - 1px);
  height: 1px;
  background-color: var(--line);
  transition: background-color 0.3s ease;
}
.tl-item.is-lit::before { background-color: var(--pc, var(--accent)); }

/* Zwei Sachen, die hier bewusst so herum stehen:

   1. Langform background-color statt der Kurzform background. Eine
      Kurzform mit var() darin wird erst spaeter aufgeloest und setzt sich
      dann in der Kaskade nicht gegen eine konkurrierende Regel durch.
   2. Der GRUNDZUSTAND ist erreicht, also farbig. JavaScript nimmt die
      Farbe wieder weg, solange die Linie den Punkt nicht erreicht hat.
      Umgekehrt haetten die Punkte ohne JavaScript grau bleiben muessen. */

.tl-dot {
  position: absolute;
  /* Mitte des Punktes genau auf die Mitte der Linie, auf Hoehe des Stegs */
  left: calc(var(--tl-line) + 1px - var(--tl-pad) - var(--tl-dot) / 2);
  top: calc(1.6rem - var(--tl-dot) / 2);
  width: var(--tl-dot);
  height: var(--tl-dot);
  border-radius: 50%;
  border-style: solid;
  border-width: 2px;
  background-color: var(--pc, var(--accent));
  border-color: var(--pc, var(--accent));
  transform: scale(1.15);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--pc, var(--accent)) 16%, transparent);
  transition: background-color 0.3s ease, border-color 0.3s ease,
              box-shadow 0.3s ease, transform 0.3s ease;
}
.js .tl-item:not(.is-lit) .tl-dot {
  background-color: var(--bg);
  border-top-color: var(--line);
  border-right-color: var(--line);
  border-bottom-color: var(--line);
  border-left-color: var(--line);
  transform: none;
  box-shadow: none;
}

/* Zeitraum als kleiner Chip in der Farbe des Schritts */
.tl-when {
  display: inline-block;
  margin-bottom: 0.7rem;
  padding: 0.18rem 0.6rem;
  border-radius: 999px;
  background-color: var(--pc-soft, var(--accent-soft));
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--pc, var(--accent));
  transition: color 0.3s ease, background-color 0.3s ease;
}
.js .tl-item:not(.is-lit) .tl-when {
  background-color: var(--card-2);
  color: var(--ink-3);
}

.tl-item h3 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.4375rem;
  line-height: 1.2;
  letter-spacing: -0.015em;
  margin: 0 0 0.3rem;
  color: var(--ink);
}

/* Institution, wie die Zeile unter einer Station im Lebenslauf */
.tl-where {
  margin: 0 0 0.9rem;
  max-width: 34rem;
  font-size: 0.9375rem;
  font-style: italic;
  color: var(--ink-3);
}

/* Stichpunkte. Der Aufzaehlungsstrich ist ein feiner Strich in der Farbe
   des Schritts, kein runder Punkt: das wirkt ruhiger und weniger nach Liste. */
.tl-facts {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 36rem;
}
.tl-facts li {
  position: relative;
  padding-left: 1.35rem;
  margin-bottom: 0.4rem;
  color: var(--ink-2);
  font-size: 0.9688rem;
  line-height: 1.55;
}
.tl-facts li:last-child { margin-bottom: 0; }
.tl-facts li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.72em;
  width: 0.7rem;
  height: 1px;
  background-color: var(--pc, var(--accent));
  opacity: 0.55;
}

/* Der letzte Schritt ist die Gegenwart und darf auffallen */
.tl-now h3 { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.tl-now h3::after {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background-color: var(--c-orange);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--c-orange) 55%, transparent);
  animation: puls 2.4s ease-out infinite;
}
@keyframes puls {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--c-orange) 55%, transparent); }
  70%  { box-shadow: 0 0 0 9px color-mix(in srgb, var(--c-orange) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--c-orange) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .tl-now h3::after { animation: none; }
}

/* ==========================================================================
   Über mich
   ========================================================================== */

.prose { max-width: var(--text); }
.prose p { margin: 0 0 1.15rem; color: var(--ink-2); }
.prose p:last-child { margin-bottom: 0; }

/* Zwischentitel. Klein und gesperrt, mit feiner Linie darueber: gliedert
   den laengeren Text, ohne wie eine zweite Ueberschriftenebene zu wirken. */
.prose-h {
  margin: 2.75rem 0 1rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line-2);
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.prose-h:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.prose-h + p { font-size: 1.0938rem; color: var(--ink); }

/* Letzter Satz, steht fuer sich */
.prose-schluss {
  margin-top: 1.75rem;
  font-family: var(--serif);
  font-size: 1.3125rem;
  font-style: italic;
  line-height: 1.4;
  color: var(--ink);
}

.facts {
  list-style: none;
  margin: 2.5rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 1px;
  background-color: var(--line);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
}
.facts li {
  padding: 1.05rem 1.15rem;
  background-color: var(--card);
  font-size: 0.9375rem;
}
.facts .k {
  display: block;
  margin-bottom: 0.2rem;
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.facts .v { display: block; }

/* ==========================================================================
   Zahlenband

   Liegt zwischen Projekten und Zeitstrahl und bricht die lange helle
   Strecke. Bewusst flach gehalten: es ist ein Trenner, kein Abschnitt.
   ========================================================================== */

.band-zahlen {
  background-color: var(--dk-bg);
  color: var(--dk-ink);
  overflow: hidden;
  isolation: isolate;
}
.band-zahlen::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(circle at 1px 1px, rgba(255, 255, 255, 0.055) 1px, transparent 0),
    radial-gradient(34rem 16rem at 82% 130%, rgba(90, 148, 202, 0.22), transparent 70%);
  background-size: 26px 26px, auto;
}

.zahlen { padding-top: 3.25rem; padding-bottom: 3.25rem; }

.zahlen ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.5rem 2rem;
}
.zahlen li {
  position: relative;
  padding-left: 1.5rem;
}
/* Feiner senkrechter Strich statt Trennlinien durch die ganze Reihe */
.zahlen li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.35rem;
  bottom: 0.35rem;
  width: 1px;
  background-image: linear-gradient(to bottom,
                    transparent, var(--dk-line), transparent);
}

.zahlen .z {
  display: block;
  font-family: var(--serif);
  font-size: clamp(2.5rem, 5vw, 3.5rem);
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--dk-ink);
  font-variant-numeric: tabular-nums;
}
.zahlen .l {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.8125rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--dk-ink2);
}

@media (max-width: 44rem) {
  .zahlen ul { grid-template-columns: repeat(2, 1fr); gap: 1.75rem 1.25rem; }
}

/* ==========================================================================
   Kontakt, dunkel
   ========================================================================== */

.band-contact h2 { color: var(--dk-ink); }
.band-contact .section-sub { color: var(--dk-ink2); }
.band-contact :focus-visible { outline-color: var(--dk-acc); }

.contact-line { margin: 0 0 1.6rem; }

.mail {
  font-family: var(--serif);
  font-size: clamp(1.5rem, 4.4vw, 2.5rem);
  letter-spacing: -0.02em;
  color: var(--dk-ink);
  border-bottom: 2px solid rgba(143, 189, 230, 0.35);
  padding-bottom: 0.12rem;
  transition: border-color 0.16s ease, color 0.16s ease;
}
.mail:hover { color: var(--dk-acc); border-bottom-color: var(--dk-acc); }

.contact-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--dk-line);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--dk-ink2);
  font-size: 0.875rem;
  font-weight: 500;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.chip svg { flex: none; }
.chip:hover {
  background: rgba(255, 255, 255, 0.09);
  border-color: rgba(255, 255, 255, 0.28);
  color: var(--dk-ink);
}

/* ==========================================================================
   Fuß
   ========================================================================== */

.foot {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 2rem 1.5rem 3rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.5rem 1.5rem;
  font-size: 0.875rem;
  color: var(--ink-3);
}
.foot p { margin: 0; }
.foot-legal { display: flex; flex-wrap: wrap; gap: 0.4rem 1.25rem; }
.foot-legal a { color: var(--ink-3); }
.foot-legal a:hover { color: var(--accent); }

/* ==========================================================================
   Einblenden beim Scrollen. Greift nur, wenn JavaScript laeuft.
   ========================================================================== */

.js [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.2, 0.7, 0.3, 1);
  will-change: opacity, transform;
}
.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* ---------- Gestaffeltes Intro im Kopf ----------
   Baut sich einmal beim Laden auf, Zeile fuer Zeile.

   Bewusst eine CSS-Animation und kein von JavaScript geschalteter Zustand:
   der Ruhezustand ist SICHTBAR, nur waehrend der Animation ist das Element
   verschoben (dafuer sorgt fill-mode backwards). Laeuft die Animation
   nicht, etwa in einem Hintergrund-Tab oder ohne JavaScript, steht der
   Text trotzdem da. Ein per rAF gesetzter Zustand hatte hier schon einen
   leeren Kopfblock verursacht. */

.js [data-stagger] {
  animation: intro-rein 0.85s cubic-bezier(0.16, 0.8, 0.28, 1) backwards;
}
@keyframes intro-rein {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 1; transform: none; }
}

.js [data-stagger="1"] { animation-delay: 0.06s; }
.js [data-stagger="2"] { animation-delay: 0.16s; }
.js [data-stagger="3"] { animation-delay: 0.28s; }
.js [data-stagger="4"] { animation-delay: 0.40s; }
.js [data-stagger="5"] { animation-delay: 0.52s; }

@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .js [data-stagger] { animation: none; }
}

/* ==========================================================================
   Fehlerseite
   ========================================================================== */

.seite-404 .band-top {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
/* In einer Flex-Spalte heben die automatischen Seitenraender von .top die
   Streckung auf, dadurch schrumpft die Kopfzeile auf ihre Inhaltsbreite und
   rutscht in die Mitte. Die volle Breite hier wieder erzwingen. */
.seite-404 .top { width: 100%; }

.fehler {
  position: relative;
  z-index: 2;
  flex: 1;
  display: grid;
  place-content: center;
  text-align: center;
  max-width: 38rem;
  margin: 0 auto;
  padding: 2rem 1.5rem 6rem;
}

.fehler-code {
  margin: 0 0 0.5rem;
  font-family: var(--serif);
  font-size: clamp(5rem, 17vw, 9rem);
  line-height: 1;
  letter-spacing: -0.04em;
  background: linear-gradient(96deg, #9fc7ee 0%, #b79bf0 48%, #e8b571 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  opacity: 0.85;
}

.fehler h1 {
  font-size: clamp(1.625rem, 4.5vw, 2.5rem);
  line-height: 1.15;
  margin: 0 0 1rem;
}

.fehler-text {
  margin: 0 0 2.25rem;
  color: var(--dk-ink2);
}

.fehler .btn { display: inline-block; }

/* ==========================================================================
   Impressum und Datenschutz
   ========================================================================== */

.page {
  max-width: 46rem;
  margin: 0 auto;
  padding: 3.5rem 1.5rem 1rem;
}
.page h1 {
  font-size: clamp(2rem, 4.5vw, 2.75rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin-bottom: 1rem;
  color: var(--ink);
}
.page-intro {
  margin: 0 0 2.5rem;
  font-size: 1.0625rem;
  color: var(--ink-2);
}

.legal { margin: 0; }
.legal dt {
  margin: 0 0 0.35rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--line-2);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.legal dt:first-child { padding-top: 0; border-top: 0; }
.legal dd { margin: 0 0 1.4rem; color: var(--ink-2); }
.legal dd strong { color: var(--ink); }

/* Noch auszufuellende Stelle. Faellt absichtlich auf. */
.legal dd.todo {
  padding: 0.7rem 0.9rem;
  border-left: 3px solid #c2801f;
  background: rgba(194, 128, 31, 0.08);
  border-radius: 0 8px 8px 0;
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   Schmale Bildschirme
   ========================================================================== */

@media (max-width: 62rem) {
  /* Vorschaubild unter den Text, sonst wird die Textspalte zu schmal */
  .project { grid-template-columns: 3.5rem minmax(0, 1fr); }
  .project-shot {
    grid-column: 1 / -1;
    margin-top: 1.4rem;
    max-width: 27rem;
    transform: none;
  }

  .hero {
    grid-template-columns: 1fr;
    gap: 2.75rem;
    padding: 3rem 1.5rem 3.5rem;
    min-height: 0;
  }
  .hero-photo { order: -1; max-width: 17rem; }
  .hero-photo img { aspect-ratio: 1 / 1; border-radius: 14px; }
  h1 { font-size: clamp(2.75rem, 12vw, 4.5rem); }
}

/* Kopf umbrechen: Name in die erste Zeile, Navigation und Sprache darunter.
   Sonst draengen sich vier Links plus Umschalter auf einer Handybreite.
   Die Navigation darf zusaetzlich selbst umbrechen: auf 320 Pixel wurde
   der EN-Knopf sonst vom Bandrand abgeschnitten. */
@media (max-width: 44rem) {
  .top { flex-wrap: wrap; row-gap: 0.9rem; }
  .top-right {
    width: 100%;
    justify-content: space-between;
    align-items: flex-end;
    gap: 0.6rem 1rem;
    flex-wrap: wrap;
  }
  .nav { flex-wrap: wrap; row-gap: 0.35rem; }
  /* Haelt den Umschalter rechts, auch wenn er in eine eigene Zeile rutscht */
  .langswitch { margin-left: auto; }
}

@media (max-width: 34rem) {
  body { font-size: 1rem; }
  .top { padding: 1.25rem 1.25rem 0; }
  .nav { gap: 0.35rem 1rem; font-size: 0.875rem; }
  .section { padding: 3.25rem 1.25rem; }
  .page { padding: 2.5rem 1.25rem 1rem; }
  .hero { padding: 2.25rem 1.25rem 2.75rem; }
  .scrollcue { display: none; }

  .project {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
    padding: 1.5rem 1.35rem 1.25rem;
  }
  .project-shot { grid-column: 1; max-width: none; margin-top: 1.25rem; }
  .project-no { font-size: 1.5rem; margin-bottom: 0.5rem; }

  /* Zeitstrahl schmaler einruecken, sonst bleibt fuer den Text zu wenig.
     Punkt und Linie folgen den Variablen automatisch. */
  .timeline { --tl-pad: 2.25rem; --tl-line: 0.3rem; }
  .tl-facts li { padding-left: 1.1rem; }
  .tl-facts li::before { width: 0.55rem; }
  .project-meta { flex-wrap: wrap; gap: 0.5rem; }
  .hero-actions .btn { flex: 1 1 auto; text-align: center; }
}
