:root{
  --star-white:#eef4ff;
  --star-blue:#9fc9ff;
  --star-warm:#ffe9c7;
  --nebula-blue:#1e3a8a;
  --nebula-purple:#4c1d95;
  --nebula-magenta:#7c2d5c;
  --accent:#7db8ff;
  --bg:#04050a;
  --glitch1:#ff2fd0;
  --glitch2:#2fe5ff;
}

*{box-sizing:border-box; margin:0; padding:0;}
html, body{
  height:100%;
  /* Pinch-Zoom & Bounce/Overscroll unterbinden - sonst geraet auf dem
     Handy die feste Positionierung (Hintergrund, Sektionen, Scroll-
     Berechnung) durcheinander und man muss neu laden. */
  touch-action:pan-y;
  overscroll-behavior:none;
  -webkit-text-size-adjust:100%;
  /* Native Scrollleiste ausblenden - eigene Anzeige (.scroll-rail) links
     uebernimmt das stattdessen. */
  scrollbar-width:none;
  -ms-overflow-style:none;
}
html::-webkit-scrollbar, body::-webkit-scrollbar{
  width:0; height:0; display:none;
}
body{
  background:var(--bg);
  color:var(--star-white);
  font-family:'Segoe UI', Arial, sans-serif;
  overflow:hidden;
}
body.ready{ overflow-y:auto; }

/* ===== Eigene Scroll-Anzeige (links) statt der ausgeblendeten Browser-
   Scrollleiste. Duenne Schiene, Fuellstand = Scroll-Fortschritt der
   gesamten Seite, wird per JS (main.js) auf Basis von window.scrollY
   gesetzt. ===== */
.scroll-rail{
  position:fixed;
  left:20px;
  top:50%;
  transform:translateY(-50%);
  width:2px;
  height:36vh;
  background:rgba(255,255,255,.14);
  border-radius:2px;
  z-index:40;
  opacity:0;
  transition:opacity .6s ease;
  pointer-events:none;
}
body.ready .scroll-rail{ opacity:1; }

/* Auf schmalen Handy-Breiten reichen zentrierte Inhalte (Panels, Karten,
   Dashboard-Mockup) nah genug an den linken Rand, dass sie sich mit der
   Leiste bei 20px ueberschneiden koennen. Auf kleinen Screens ruecken wir
   sie daher ganz an den Rand und machen sie etwas kuerzer/dezenter, damit
   sie zuverlaessig aus dem Weg ist statt ueber Inhalt zu liegen. */
@media (max-width: 600px){
  .scroll-rail{
    left:6px;
    height:26vh;
  }
}
.scroll-rail-fill{
  position:absolute;
  left:0; top:0;
  width:100%;
  height:0%;
  background:linear-gradient(var(--star-white), var(--star-blue));
  border-radius:2px;
  box-shadow:0 0 10px rgba(125,184,255,.7);
  transition:height .2s linear;
}

/* ===== Tipp-Button unten: ein Antippen = ein Scroll-Schritt weiter.
   main.js blendet ihn per "show"-Klasse aus, sobald man auf der letzten
   Sektion (Kontakt) angekommen ist - da gibt es nichts mehr weiter. ===== */
.scroll-tap-btn{
  position:fixed;
  left:50%;
  bottom:26px;
  transform:translateX(-50%);
  width:52px; height:52px;
  border-radius:50%;
  border:1px solid rgba(255,255,255,.25);
  background:rgba(255,255,255,.06);
  backdrop-filter:blur(6px);
  color:var(--star-blue);
  font-size:1.2rem;
  display:flex; align-items:center; justify-content:center;
  cursor:pointer;
  z-index:45;
  opacity:0;
  pointer-events:none;
  transition:opacity .4s ease, background .2s ease, border-color .2s ease, box-shadow .2s ease;
}
.scroll-tap-btn.show{
  opacity:.85;
  pointer-events:auto;
}
.scroll-tap-btn:hover{
  background:rgba(125,184,255,.16);
  border-color:rgba(125,184,255,.55);
  box-shadow:0 0 20px rgba(125,184,255,.35);
}
.scroll-tap-btn:active{
  transform:translateX(-50%) scale(.92);
}

/* ===== Matrix intro ===== */
#matrix-intro{
  position:fixed; inset:0; z-index:99;
  background:#020203;
  opacity:0;
  pointer-events:none;
  transition:opacity .4s ease;
  overflow:hidden;
}
#matrix-intro.active{ opacity:1; pointer-events:auto; }
#matrix-intro.fade-out{ opacity:0; }

#matrix-output{
  position:absolute; top:0; left:0; right:0;
  margin:0;
  padding:2vh 3vw;
  font-family:'Consolas','Courier New',monospace;
  font-size:clamp(.7rem, 1.4vw, .95rem);
  line-height:1.5;
  color:#6fffb0;
  text-align:left;
  white-space:pre-wrap;
  word-break:break-all;
  text-shadow:0 0 6px rgba(111,255,176,.5);
  will-change:transform;
}

/* ===== Galaxy background ===== */
/* Startet unsichtbar und baut sich erst waehrend/nach dem Jawas.de-Aufbau auf. */
#galaxy-canvas{
  position:fixed; inset:0; width:100%; height:100%; z-index:0;
  opacity:0;
  transition:opacity 2.2s ease;
}
#galaxy-canvas.live{ opacity:1; }

#nebula-layer{
  position:fixed; inset:-10%; width:120%; height:120%; z-index:0;
  pointer-events:none;
  opacity:0;
  background:
    radial-gradient(ellipse 40% 30% at 20% 30%, rgba(76,29,149,.35), transparent 60%),
    radial-gradient(ellipse 35% 25% at 75% 60%, rgba(30,58,138,.3), transparent 60%),
    radial-gradient(ellipse 30% 35% at 60% 15%, rgba(124,45,92,.22), transparent 60%),
    radial-gradient(ellipse 45% 40% at 40% 85%, rgba(15,23,42,.4), transparent 65%);
  filter:blur(40px);
  animation:nebulaDrift 40s ease-in-out infinite alternate;
  transition:opacity 2.6s ease;
  will-change:transform, opacity;
}
#nebula-layer.live{ opacity:1; }
@keyframes nebulaDrift{
  from{ transform:translate(0,0) scale(1); }
  to{ transform:translate(-2%,1.5%) scale(1.05); }
}

/* ===== Main site ===== */
#site{
  position:relative; z-index:2;
  min-height:100vh;
  min-height:100dvh;
}
#site.hidden{ display:none; }

.snap-section{
  height:100vh;
  height:100dvh; /* korrekte Hoehe auf Handys statt durch die Adressleiste versetzt */
  width:100%;
  background:transparent; /* das Universum dahinter bleibt durchgehend sichtbar */
}

.hero{
  height:100vh;
  height:100dvh;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  text-align:center; padding:2rem;
}
.logo-stage{
  position:relative;
  display:flex;
  justify-content:center;
}
/* Kurzer Blitz-Text, der vor dem eigentlichen Logo-Aufbau erscheint,
   sofort heftig glitcht und dann wegblitzt - JAWAS.DE baut sich erst
   danach auf (siehe playLogoIntro() in main.js). */
.logo-flash{
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  font-family:'Wallpoet', 'Segoe UI', Arial, sans-serif;
  font-size:clamp(1.8rem, 7.5vw, 4.2rem);
  font-weight:400;
  letter-spacing:3px;
  color:var(--star-warm);
  text-shadow:0 0 30px rgba(255,233,199,.55), 0 0 80px rgba(180,120,40,.4);
  opacity:0;
  pointer-events:none;
  transition:opacity .05s linear;
}
.logo-flash.show{ opacity:1; }
.logo-flash.glitching{
  animation: glitchShake .1s steps(2, end) infinite;
}
.logo-flash.glitching::before,
.logo-flash.glitching::after{
  content:attr(data-text);
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  pointer-events:none;
  mix-blend-mode:screen;
}
.logo-flash.glitching::before{
  color:var(--glitch1);
  animation:glitchLayerA .38s steps(3, end) infinite;
}
.logo-flash.glitching::after{
  color:var(--glitch2);
  animation:glitchLayerB .32s steps(3, end) infinite;
}

/* Logo + Tagline stehen jetzt als eine Einheit "im Ring" (siehe .saturn-
   ring unten) - eigener Stacking-Context (z-index:1), damit beide
   zusammen zwischen ring-back (0) und ring-front (2) liegen. */
.hero-text{
  position:relative;
  z-index:1;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:.9rem;
}
.logo{
  position:relative;
  display:flex; justify-content:center;
  font-family:'Wallpoet', 'Segoe UI', Arial, sans-serif;
  font-size:clamp(1.8rem, 7.5vw, 4.2rem);
  font-weight:400;
  letter-spacing:3px;
  /* Schwarze Buchstaben mit leuchtendem Rand statt durchgehend heller
     Fuellung - der Kontur-Stroke zeichnet die scharfe Kante, text-shadow
     sorgt zusaetzlich fuer das weiche Glow-Bleeding drumherum. Gleiche
     Weiss/Blau-Glow-Palette wie beim Karten-Rand (corner-trace/hover). */
  color:#000;
  -webkit-text-stroke:2px var(--accent);
  text-stroke:2px var(--accent);
}
/* Saturnring um Logo + Tagline zusammen: obere Haelfte (ring-back) liegt
   hinter dem Text, untere Haelfte (ring-front) davor - dadurch wirkt es,
   als liefe der Ring wirklich um beide Zeilen herum. Faehrt erst hoch,
   sobald der Buchstaben-Aufbau fertig ist. Fixe Drehung gegen den
   Uhrzeigersinn (statt achsenparallel-flach) fuer den typischen schraeg
   gekippten Saturnring-Look - bleibt aber KONSTANT (keine Animation der
   Drehung selbst), sonst "flippt" die Form sichtbar; nur die einzelnen
   Partikel bewegen sich (siehe .ring-particle/animateMotion). */
.saturn-ring{
  position:absolute;
  left:50%;
  top:50%;
  transform:translate(-50%, -50%) rotate(-18deg);
  /* Kleiner/kompakter als zuvor und dafuer weniger flach (mehr Hoehe
     relativ zur Breite) - sonst ist die Ellipse insgesamt breiter als der
     Textblock und die Vorne/Hinten-Kante laeuft komplett seitlich am Text
     vorbei, statt sichtbar ueber die Buchstaben zu kreuzen. */
  width:clamp(320px, 45vw, 620px);
  aspect-ratio:400 / 170;
  pointer-events:none;
  overflow:visible;
  opacity:1;
}
.ring-back{ z-index:0; }
.ring-front{ z-index:2; }
/* Der Ring besteht komplett aus einzelnen kleinen Partikeln (zwei Reihen
   = Ringbreite, Luecke dazwischen wie die Cassini-Teilung) statt aus
   durchgezogenen Linien. Jeder Partikel wandert einzeln per SMIL
   (animateMotion, siehe index.html) entlang der jeweils gleichen fest-
   stehenden Ellipsenbahn - die Ellipse selbst dreht/kippt sich NICHT (das
   sah wie ein Flip aus), nur die Partikel gleiten darauf entlang, wie
   echter Ringstaub. Innere Reihe dreht schneller als die aeussere (wie in
   echten Planetenringen: naeher am Zentrum = schnellerer Umlauf). */
/* Matte, erdig-graue/sandige Toene statt leuchtendem Weiss/Warm - echter
   Ringstaub reflektiert nur schwach, er glueht nicht wie ein Stern. Kein
   drop-shadow-Glow mehr, kaum/kein Funkeln (nur ein Hauch Schimmer statt
   Stern-Twinkle), damit es sich klar von den Hintergrundsternen abhebt.
   Deutlich mehr/kleinere Partikel als vorher, dichter gepackt entlang der
   Bahn, damit sie als zusammenhaengendes Band statt als Punktwolke wirken. */
.ring-particle{
  fill:#6b6e73;
  opacity:1;
}
.ring-particle:nth-of-type(4n){ fill:#4a4d52; }
.ring-particle:nth-of-type(4n+1){ fill:#9a9ea3; }
.ring-particle:nth-of-type(4n+2){ fill:#7d7f83; }
.logo span{
  display:inline-block;
  opacity:0;
  transform:translateY(28px);
  text-shadow:0 0 8px rgba(255,255,255,.9), 0 0 22px rgba(125,184,255,.65), 0 0 60px rgba(125,184,255,.4);
  animation:letterIn .5s forwards;
  /* Bleibt zunaechst pausiert (= unsichtbar, wie der Start-Zustand) bis
     main.js nach dem UTINNI!-Blitz die Klasse "build" setzt. */
  animation-play-state:paused;
}
.logo.build span{
  animation-play-state:running;
}
.logo span:nth-child(1){ animation-delay:.05s; }
.logo span:nth-child(2){ animation-delay:.16s; }
.logo span:nth-child(3){ animation-delay:.27s; }
.logo span:nth-child(4){ animation-delay:.38s; }
.logo span:nth-child(5){ animation-delay:.49s; }
.logo span:nth-child(6){ animation-delay:.60s; }
.logo span:nth-child(7){ animation-delay:.71s; }
.logo span:nth-child(8){ animation-delay:.82s; }
@keyframes letterIn{
  to{ opacity:1; transform:translateY(0); }
}

/* Heftiges Flimmern beim Sektionswechsel (Klasse wird per JS kurz gesetzt).
   Die echten Buchstaben-Spans werden bewusst NICHT per CSS-Animation
   angefasst (sonst wuerde die letterIn-Aufbauanimation beim Entfernen der
   Klasse erneut abgespielt) - das Flackern der Spans passiert per JS ueber
   inline opacity. Das ganze Wort ruckelt zusaetzlich per CSS, dazu die
   geisterhaften RGB-Split-Ebenen - beides laeuft "infinite" solange die
   Klasse gesetzt ist, fuer ein deutlich heftigeres Flackern. */
.logo.glitching{
  animation: glitchShake .1s steps(2, end) infinite;
}
@keyframes glitchShake{
  0%{ transform:translate(0,0) skewX(0deg); }
  25%{ transform:translate(-5px,3px) skewX(-3deg); }
  50%{ transform:translate(5px,-3px) skewX(3deg); }
  75%{ transform:translate(-4px,-4px) skewX(-2deg); }
  100%{ transform:translate(3px,4px) skewX(2deg); }
}

.logo.glitching::before,
.logo.glitching::after{
  content:attr(data-text);
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center;
  pointer-events:none;
  mix-blend-mode:screen;
}
.logo.glitching::before{
  color:var(--glitch1);
  animation:glitchLayerA .38s steps(3, end) infinite;
}
.logo.glitching::after{
  color:var(--glitch2);
  animation:glitchLayerB .32s steps(3, end) infinite;
}
@keyframes glitchLayerA{
  0%{ opacity:0; transform:translate(0,0); clip-path:inset(0 0 85% 0); }
  15%{ opacity:1; transform:translate(-10px,2px); clip-path:inset(10% 0 55% 0); }
  30%{ opacity:.3; transform:translate(8px,-3px); clip-path:inset(55% 0 10% 0); }
  45%{ opacity:1; transform:translate(-9px,0); clip-path:inset(20% 0 65% 0); }
  60%{ opacity:.2; transform:translate(10px,3px); clip-path:inset(70% 0 5% 0); }
  75%{ opacity:1; transform:translate(-7px,-2px); clip-path:inset(5% 0 80% 0); }
  90%{ opacity:.4; transform:translate(6px,0); clip-path:inset(45% 0 25% 0); }
  100%{ opacity:0; transform:translate(0,0); clip-path:inset(0 0 100% 0); }
}
@keyframes glitchLayerB{
  0%{ opacity:0; transform:translate(0,0); clip-path:inset(85% 0 0 0); }
  15%{ opacity:1; transform:translate(9px,-2px); clip-path:inset(45% 0 30% 0); }
  30%{ opacity:.3; transform:translate(-8px,3px); clip-path:inset(10% 0 60% 0); }
  45%{ opacity:1; transform:translate(7px,0); clip-path:inset(65% 0 10% 0); }
  60%{ opacity:.2; transform:translate(-10px,-3px); clip-path:inset(30% 0 50% 0); }
  75%{ opacity:1; transform:translate(8px,2px); clip-path:inset(5% 0 85% 0); }
  90%{ opacity:.4; transform:translate(-6px,0); clip-path:inset(60% 0 15% 0); }
  100%{ opacity:0; transform:translate(0,0); clip-path:inset(100% 0 0 0); }
}

.tagline{
  font-size:clamp(1rem, 2vw, 1.3rem);
  color:var(--star-blue);
  letter-spacing:1px;
  opacity:0;
  transition:opacity 1s ease;
}
.tagline.show{ opacity:.85; }

.tilt-btn{
  margin-top:1.4rem;
  cursor:pointer;
  font-family:inherit;
  font-size:.9rem;
  font-weight:600;
  letter-spacing:.5px;
  padding:.6rem 1.4rem;
  border-radius:50px;
  border:1px solid rgba(159,201,255,.5);
  background:rgba(159,201,255,.08);
  color:var(--star-blue);
  opacity:0;
  transition:opacity .6s ease, transform .2s ease, background .2s ease;
}
.tilt-btn.show{ opacity:.9; }
.tilt-btn:active{ transform:scale(.96); background:rgba(159,201,255,.18); }
.tilt-btn[hidden]{ display:none; }

/* ===== Neue Sektion: Portfolio mit schwebenden, anklickbaren
   Projekt-Boxen. Klick oeffnet das Overlay weiter unten. ===== */
.section-portfolio{
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  padding:2rem;
}
.portfolio-title{
  font-family:'Orbitron', sans-serif;
  font-weight:800;
  font-size:clamp(1.6rem, 4vw, 2.6rem);
  letter-spacing:.04em;
  color:var(--star-white);
  text-shadow:0 0 20px rgba(125,184,255,.5), 0 0 44px rgba(125,184,255,.25);
  text-align:center;
  margin-bottom:2.2rem;
}
.portfolio-grid{
  display:flex;
  flex-wrap:wrap;
  gap:1.6rem;
  justify-content:center;
  align-items:center;
  opacity:0;
  transform:translateY(40px);
  transition:opacity .7s ease, transform .7s cubic-bezier(.22,.75,.2,1);
}
.portfolio-grid.in{
  opacity:1;
  transform:translateY(0);
}
.project-box{
  position:relative;
  cursor:pointer;
  width:min(220px, 40vw);
  /* Seitenverhaeltnis der Mobile-Screenshots (549x994) - die Box bekommt
     dadurch automatisch die passende Hoehe, das Bild muss nicht verzerrt
     oder stark beschnitten werden. */
  aspect-ratio:549 / 994;
  border-radius:20px;
  overflow:hidden;
  background-size:cover;
  background-position:top center;
  background-color:#0a0d16;
  border:1px solid rgba(255,255,255,.15);
  transition:box-shadow .35s ease, border-color .35s ease, transform .45s cubic-bezier(.22,.75,.2,1), opacity .35s ease;
  animation:boxFloat 5s ease-in-out infinite;
}
.project-box:nth-child(2){
  animation-delay:-2.3s;
}
.project-box:hover{
  border-color:rgba(125,184,255,.4);
  box-shadow:0 0 34px rgba(125,184,255,.32), inset 0 0 16px rgba(125,184,255,.14);
}

/* Auf schmalen Handys etwas kleiner skaliert, sonst gleiches Layout. */
@media (max-width: 600px){
  .section-portfolio{
    padding:1.2rem;
  }
  .portfolio-title{
    font-size:1.4rem;
    margin-bottom:1.1rem;
  }
  .portfolio-grid{
    gap:1.1rem;
  }
  .project-box{
    width:min(150px, 34vw);
  }
  .desk-bg{
    height:min(54.5vw, 260px);
    opacity:.85;
  }
}

/* Umrandungs-Effekt als echter SVG-Pfad statt einzelner CSS-Balken - nur
   so folgt die Linie dem 20px-Radius der Box wirklich durchgehend (echte
   Kreisboegen statt angenaeherter Ecken-Elemente, die sich ueberschnitten
   oder eckig aneinandertrafen). Zwei Pfade (trace-a: oben-links -> oben ->
   oben-rechts -> rechts; trace-b: unten-rechts -> unten -> unten-links ->
   links), jeweils exakt die Haelfte des Umfangs. d/Laenge werden von
   main.js pro Box anhand der tatsaechlichen Groesse berechnet (initProject
   BoxTraces). Im Ruhezustand ist genau der erste Viertelkreis (die Ecke
   selbst) sichtbar; beim Hover zieht sich die Linie in einem Zug im
   Uhrzeigersinn weiter bis beide Haelften sich schliessen. */
.corner-trace{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  overflow:visible;
  pointer-events:none;
  /* Muss ueber dem Textverlauf (.project-box-label, z-index:1) liegen -
     sonst verschwindet die untere rechte Eckmarkierung unsichtbar unter
     dessen dunklem Hintergrund, obwohl sie geometrisch exakt richtig
     positioniert ist. */
  z-index:2;
}
.trace-path{
  fill:none;
  stroke:var(--star-white);
  stroke-width:3.5px;
  filter:drop-shadow(0 0 5px rgba(255,255,255,.65));
  transition:stroke-dashoffset .6s cubic-bezier(.22,.75,.2,1);
}
.project-box:hover .trace-path{
  stroke-dashoffset:0 !important;
}
/* Titel/Text liegen jetzt auf einem Verlauf ueber dem Screenshot, statt
   frei auf der Glas-Flaeche zu stehen - sonst waeren sie je nach Bildinhalt
   kaum lesbar. */
.project-box-label{
  position:absolute;
  left:0;
  right:0;
  bottom:0;
  z-index:1;
  padding:1.3rem 1rem 1.1rem;
  background:linear-gradient(to top, rgba(4,5,10,.92) 15%, rgba(4,5,10,.5) 60%, transparent 100%);
  text-align:center;
  pointer-events:none;
}
.project-box h3{
  font-size:1.1rem;
  color:var(--star-white);
  margin-bottom:.35rem;
  text-shadow:0 2px 8px rgba(0,0,0,.8);
}
.project-box p{
  font-size:.82rem;
  color:var(--star-blue);
  opacity:.9;
  text-shadow:0 2px 6px rgba(0,0,0,.8);
}
@keyframes boxFloat{
  0%, 100%{ transform:translateY(0); }
  50%{ transform:translateY(-14px); }
}

/* Projekt-Detail-Overlay: oeffnet sich beim Klick auf eine Box, Rest der
   Seite bleibt abgedunkelt im Hintergrund sichtbar. */
.project-modal{
  position:fixed; inset:0; z-index:60;
  display:flex; align-items:center; justify-content:center;
  opacity:0;
  pointer-events:none;
  transition:opacity .3s ease;
}
.project-modal.show{ opacity:1; pointer-events:auto; }
.project-modal-backdrop{
  position:absolute; inset:0;
  background:rgba(2,3,6,.75);
  backdrop-filter:blur(4px);
}
.project-modal-card{
  position:relative;
  z-index:1;
  max-width:min(420px, 88vw);
  padding:2.2rem 2rem;
  border-radius:20px;
  background:linear-gradient(160deg, rgba(20,24,38,.95), rgba(8,10,18,.95));
  border:1px solid rgba(125,184,255,.3);
  box-shadow:0 0 50px rgba(125,184,255,.2);
  text-align:center;
  transform:translateY(20px) scale(.96);
  transition:transform .3s cubic-bezier(.22,.75,.2,1);
}
.project-modal.show .project-modal-card{
  transform:translateY(0) scale(1);
}
.project-modal-close{
  position:absolute; top:.6rem; right:.9rem;
  background:none; border:none;
  color:var(--star-blue);
  font-size:1.6rem;
  cursor:pointer;
  line-height:1;
}
.project-modal-card h3{
  font-size:1.4rem;
  color:var(--star-white);
  margin-bottom:.8rem;
}
.project-modal-card p{
  font-size:.95rem;
  color:var(--star-blue);
  opacity:.85;
  margin-bottom:1.4rem;
  line-height:1.5;
}
.project-modal-link{
  display:inline-block;
  padding:.7rem 1.6rem;
  border-radius:50px;
  border:2px solid var(--accent);
  color:var(--accent);
  text-decoration:none;
  font-weight:600;
  transition:background .25s ease, color .25s ease;
}
.project-modal-link:hover{
  background:var(--accent);
  color:#04050a;
}

/* Kontakt-Formular-Overlay: gleiche Optik/Technik wie das Projekt-Overlay
   (abgedunkelter Hintergrund, zentrierte Karte), nur breiter fuer die
   Formularfelder. */
.contact-modal{
  position:fixed; inset:0; z-index:60;
  display:flex; align-items:center; justify-content:center;
  opacity:0;
  pointer-events:none;
  transition:opacity .3s ease;
  padding:1.5rem;
}
.contact-modal.show{ opacity:1; pointer-events:auto; }
.contact-modal-backdrop{
  position:absolute; inset:0;
  background:rgba(2,3,6,.75);
  backdrop-filter:blur(4px);
}
.contact-modal-card{
  position:relative;
  z-index:1;
  width:min(440px, 92vw);
  max-height:88vh;
  overflow-y:auto;
  /* Eigene Scroll-Leiste (.scroll-rail) uebernimmt die Anzeige, die
     Browser-Scrollbar hier waere nur ein hässlicher Fremdkoerper. */
  scrollbar-width:none;
  -ms-overflow-style:none;
  padding:2.2rem 2rem;
  border-radius:20px;
  background:linear-gradient(160deg, rgba(20,24,38,.95), rgba(8,10,18,.95));
  border:1px solid rgba(125,184,255,.3);
  box-shadow:0 0 50px rgba(125,184,255,.2);
  text-align:center;
  transform:translateY(20px) scale(.96);
  transition:transform .3s cubic-bezier(.22,.75,.2,1);
}
.contact-modal.show .contact-modal-card{
  transform:translateY(0) scale(1);
}
.contact-modal-card::-webkit-scrollbar{
  width:0; height:0; display:none;
}
.contact-modal-close{
  position:absolute; top:.6rem; right:.9rem;
  background:none; border:none;
  color:var(--star-blue);
  font-size:1.6rem;
  cursor:pointer;
  line-height:1;
}
.contact-modal-card h3{
  font-size:1.4rem;
  color:var(--star-white);
  margin-bottom:1.3rem;
}
.contact-form{
  display:flex;
  flex-direction:column;
  gap:1rem;
  text-align:left;
}
.contact-form-field{
  display:flex;
  flex-direction:column;
  gap:.4rem;
  font-size:.82rem;
  color:var(--star-blue);
}
.contact-form-field input,
.contact-form-field textarea{
  font-family:inherit;
  font-size:.92rem;
  color:var(--star-white);
  background:rgba(255,255,255,.05);
  border:1px solid rgba(125,184,255,.25);
  border-radius:10px;
  padding:.65rem .8rem;
  resize:vertical;
  transition:border-color .2s ease, background .2s ease;
}
.contact-form-field input:focus,
.contact-form-field textarea:focus{
  outline:none;
  border-color:var(--accent);
  background:rgba(255,255,255,.08);
}
/* Fuer Menschen unsichtbar, aber im DOM vorhanden - Bots, die Formulare
   blind ausfuellen, tappen hier oft rein. Kein display:none, weil manche
   Bots das erkennen und das Feld dann bewusst leer lassen. */
.contact-honeypot{
  position:absolute;
  left:-9999px;
  width:1px;
  height:1px;
  overflow:hidden;
}
.contact-form-submit{
  margin-top:.3rem;
  padding:.75rem 1.6rem;
  border-radius:50px;
  border:2px solid var(--accent);
  background:transparent;
  color:var(--accent);
  font-weight:600;
  font-family:inherit;
  font-size:.95rem;
  cursor:pointer;
  transition:background .25s ease, color .25s ease, opacity .2s ease;
}
.contact-form-submit:hover{
  background:var(--accent);
  color:#04050a;
}
.contact-form-submit:disabled{
  opacity:.55;
  cursor:default;
  background:transparent;
  color:var(--accent);
}
.contact-form-status{
  min-height:1.2em;
  font-size:.85rem;
  text-align:center;
  color:var(--star-blue);
}
.contact-form-status.is-error{ color:#ff8080; }
.contact-form-status.is-success{ color:#7dffb0; }
.contact-form-alt{
  margin-top:1.4rem;
  padding-top:1.2rem;
  border-top:1px solid rgba(125,184,255,.15);
  font-size:.85rem;
  color:var(--star-blue);
  opacity:.85;
}
.contact-mail-reveal{
  color:var(--accent);
  text-decoration:underline;
  cursor:pointer;
}

/* ===== Sektion 3: Live-Dashboard-Mockup statt reinknallendem Text - ein
   glaubwuerdig wirkendes Monitoring-Fenster mit echt hochzaehlenden Live-
   Metriken + laufendem Graph (siehe tickDashboard/main.js) soll "echte
   Systeme, kein Baukasten" sichtbar beweisen statt nur zu behaupten. Kippt
   leicht mit der Maus. Darunter tippt sich eine von vier Aussagen als
   Caption ein, wechselt beim Weiterscrollen (siehe applyPitchState). */
.section-pitch{
  position:relative;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:2.2rem;
  padding:2rem;
  perspective:1200px;
}
.dash-mock{
  width:min(760px, 92vw);
  border-radius:16px;
  background:linear-gradient(160deg, rgba(255,255,255,.08), rgba(255,255,255,.02));
  border:1px solid rgba(255,255,255,.15);
  backdrop-filter:blur(10px);
  box-shadow:0 30px 80px rgba(0,0,0,.55), 0 0 40px rgba(125,184,255,.12);
  overflow:hidden;
  transform:rotateX(16deg) scale(.85);
  opacity:0;
  transition:transform .9s cubic-bezier(.2,1.2,.3,1), opacity .7s ease;
  will-change:transform;
}
.dash-mock.in{
  transform:rotateX(0deg) rotateY(0deg) scale(1);
  opacity:1;
}
.dash-chrome{
  display:flex;
  align-items:center;
  gap:.45rem;
  padding:.7rem 1rem;
  background:rgba(255,255,255,.04);
  border-bottom:1px solid rgba(255,255,255,.08);
}
.dash-dot{
  width:10px;
  height:10px;
  border-radius:50%;
}
.dash-dot-red{ background:#ff5f57; }
.dash-dot-yellow{ background:#febc2e; }
.dash-dot-green{ background:#28c840; }
.dash-url{
  margin-left:.8rem;
  font-size:.78rem;
  color:var(--star-blue);
  opacity:.75;
  font-family:'Segoe UI', Arial, sans-serif;
}
.dash-body{
  padding:1.6rem 1.8rem 1.8rem;
}
.dash-metrics{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(130px, 1fr));
  gap:1.1rem;
  margin-bottom:1.4rem;
}
.dash-metric{
  display:flex;
  flex-direction:column;
  gap:.3rem;
}
.dash-metric-label{
  font-size:.7rem;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:var(--star-blue);
  opacity:.7;
}
.dash-metric-value{
  font-family:'Orbitron', sans-serif;
  font-weight:800;
  font-size:clamp(1.15rem, 2.6vw, 1.6rem);
  color:var(--star-white);
  text-shadow:0 0 16px rgba(125,184,255,.4);
  font-variant-numeric:tabular-nums;
}
.dash-graph{
  width:100%;
  height:88px;
  display:block;
}
.pitch-caption-wrap{
  position:relative;
  z-index:2;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:1.4rem;
  max-width:760px;
  text-align:center;
}
.pitch-caption{
  font-family:'Orbitron', sans-serif;
  font-weight:700;
  font-size:clamp(1.05rem, 2.5vw, 1.5rem);
  color:var(--star-white);
  text-shadow:0 0 18px rgba(125,184,255,.45);
  min-height:2.6em;
  line-height:1.4;
}
.pitch-caption:not(:empty)::after{
  content:'';
  display:inline-block;
  width:2px;
  height:1em;
  background:var(--star-blue);
  margin-left:2px;
  vertical-align:-.15em;
  animation:pitchCursorBlink 1s step-end infinite;
}
@keyframes pitchCursorBlink{
  0%, 50%{ opacity:1; }
  51%, 100%{ opacity:0; }
}
.pitch-dots{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:.6rem;
}
.pitch-dot{
  width:7px; height:7px;
  border-radius:50%;
  background:rgba(255,255,255,.25);
  transition:background .3s ease, transform .3s ease, box-shadow .3s ease;
}
.pitch-dot.active{
  background:var(--star-blue);
  transform:scale(1.4);
  box-shadow:0 0 10px rgba(125,184,255,.7);
}

/* ===== Sektion 4: Kontakt - bewusst eigener schwarzer Hintergrund
   (einzige Ausnahme, sonst bleibt ueberall das Universum sichtbar). ===== */
.section-four{
  background:#000;
  display:flex;
  align-items:center;
  justify-content:center;
  position:relative;
  overflow:hidden;
}
/* Retro-Schreibtisch (bilder/BGDesk.png) als reine Hintergrund-Deko: das
   Bild ist bis auf den Schreibtisch selbst transparent, steht darum am
   unteren Rand der Sektion. Absolut positioniert, z-index:0 -> liegt
   hinter .contact-content (z-index:2) und .contact-burst (z-index:3). */
.desk-bg{
  position:absolute;
  left:50%;
  bottom:0;
  transform:translateX(-50%);
  width:100vw;
  height:min(54.5vw, 560px);
  background-image:url('../bilder/BGDesk.png');
  background-repeat:no-repeat;
  background-position:bottom center;
  background-size:100% auto;
  opacity:.8;
  filter:brightness(.7) saturate(.9);
  pointer-events:none;
  z-index:0;
}
/* Abdunkler: dunkelster Punkt dort, wo Titel/Button liegen (leicht ueber
   der Mitte), wird zu den Raendern/nach unten hin transparent, damit der
   Schreibtisch als Deko sichtbar bleibt, der Text davor aber immer lesbar
   ist - unabhaengig von Viewport-Groesse oder Bildinhalt an der Stelle. */
.desk-scrim{
  position:absolute;
  inset:0;
  background:radial-gradient(ellipse 65% 55% at 50% 42%, rgba(4,5,10,.8) 0%, rgba(4,5,10,.55) 45%, rgba(4,5,10,.15) 72%, transparent 100%);
  pointer-events:none;
  z-index:1;
}
.contact-content{
  position:relative;
  z-index:2;
  display:flex;
  flex-direction:column;
  align-items:center;
  text-align:center;
  padding:2rem;
  opacity:0;
  transform:translateY(90px);
  transition:opacity .8s ease, transform .8s cubic-bezier(.22,.75,.2,1);
}
.contact-content.in{
  opacity:1;
  transform:translateY(0);
}
.contact-title{
  font-family:'Orbitron', sans-serif;
  font-weight:900;
  font-size:clamp(2.2rem, 6vw, 4rem);
  letter-spacing:.03em;
  color:var(--star-white);
  text-shadow:0 2px 18px rgba(0,0,0,.85), 0 0 26px rgba(125,184,255,.55), 0 0 60px rgba(76,29,149,.4);
}
.contact-sub{
  margin-top:.9rem;
  font-size:clamp(.95rem, 1.7vw, 1.15rem);
  color:var(--star-blue);
  opacity:.9;
  text-shadow:0 2px 10px rgba(0,0,0,.85);
}

/* Energie-Kern statt der frueheren Pillen-Form - passt zum restlichen
   Weltraum-Look der Seite. Zwei versetzt gepulste Ringe drumherum laufen
   dauerhaft (wie ein Funkspruch/Radar-Ping), damit der Button auch in Ruhe
   schon lebendig wirkt statt statisch dazustehen. */
.contact-core{
  position:relative;
  margin-top:2.6rem;
  width:132px;
  height:132px;
  border-radius:50%;
  cursor:pointer;
  font-family:'Orbitron', sans-serif;
  font-weight:700;
  font-size:1.05rem;
  letter-spacing:.05em;
  color:var(--star-white);
  background:radial-gradient(circle at 50% 38%, rgba(125,184,255,.22), rgba(4,5,10,.35) 72%);
  border:2px solid rgba(125,184,255,.55);
  box-shadow:0 0 32px rgba(125,184,255,.35), inset 0 0 20px rgba(125,184,255,.16);
  display:flex;
  align-items:center;
  justify-content:center;
  transition:transform .3s cubic-bezier(.2,1.4,.3,1), box-shadow .3s ease;
}
.contact-core:hover{
  transform:scale(1.07);
  box-shadow:0 0 56px rgba(125,184,255,.6), inset 0 0 26px rgba(125,184,255,.26);
}
.contact-core:active{ transform:scale(.96); }
.contact-core-label{ position:relative; z-index:1; }
.contact-core-ring{
  position:absolute;
  inset:-16px;
  border-radius:50%;
  border:1.5px solid rgba(125,184,255,.45);
  pointer-events:none;
  animation:coreRingPulse 2.6s ease-out infinite;
}
.contact-core-ring.ring-2{ animation-delay:1.3s; }
@keyframes coreRingPulse{
  0%{ transform:scale(.82); opacity:.9; }
  100%{ transform:scale(1.55); opacity:0; }
}

/* Bestaetigungstext nach dem Klick - schnappt gross/scharf rein statt wie
   vorher ein Emoji+Herzenregen, passt so zum Rest der "Wow"-Bewegungen. */
.contact-confirm{
  margin-top:1.7rem;
  font-family:'Orbitron', sans-serif;
  font-size:clamp(1rem, 2vw, 1.25rem);
  letter-spacing:.04em;
  color:var(--star-white);
  text-shadow:0 0 18px rgba(125,184,255,.6);
  opacity:0;
  transform:translateY(14px) scale(.9);
  filter:blur(6px);
  transition:opacity .5s ease, transform .55s cubic-bezier(.2,1.4,.3,1), filter .5s ease;
}
.contact-confirm.show{
  opacity:1;
  transform:translateY(0) scale(1);
  filter:blur(0);
}

/* Energie-Ausbruch beim Klick: Ring + Funken erzeugt per JS
   (triggerContact), Positionierung (top/left) kommt dabei direkt vom
   Button - dieselbe Technik wie der Funken-Ausbruch in Sektion 2. */
.contact-burst{
  position:absolute;
  inset:0;
  pointer-events:none;
  overflow:visible;
  z-index:3;
}
.contact-spark{
  position:absolute;
  width:4px;
  height:4px;
  border-radius:50%;
  background:var(--star-white);
  box-shadow:0 0 7px 1px rgba(125,184,255,.85), 0 0 3px rgba(255,255,255,.9);
  opacity:0;
  animation:contactSpark .78s cubic-bezier(.16,.8,.3,1) forwards;
}
@keyframes contactSpark{
  0%{
    opacity:1;
    transform:translate(-50%,-50%) translate(0,0) scale(1);
  }
  100%{
    opacity:0;
    transform:translate(-50%,-50%) translate(var(--spark-x,0), var(--spark-y,0)) scale(.2);
  }
}
.contact-shock{
  position:absolute;
  width:16px;
  height:16px;
  border:2px solid rgba(255,255,255,.85);
  border-radius:50%;
  transform:translate(-50%,-50%);
  box-shadow:0 0 26px 5px rgba(125,184,255,.55);
  pointer-events:none;
  animation:contactShock .65s cubic-bezier(.2,.7,.3,1) forwards;
}
@keyframes contactShock{
  0%{ width:16px; height:16px; opacity:1; }
  100%{ width:440px; height:440px; opacity:0; }
}
