/* ==========================================================================
   Nexus-Prompt - Startseite (Intro)
   Aus dem Startbild von Nexus-Prompt v2.10.0 herausgelöst: rotierendes
   3D-Logo, Blitze, Schriftzüge im Takt, Lichthof, Pulsieren zur Musik.
   Ohne Anmeldefenster und ohne externe Schriftarten.

   Urheber: Martin Arndt.
   ========================================================================== */

:root {
  --bg:         #080a0f;
  --text:       #f2f2f5;
  --text-faint: #6b6b76;
  --accent:     #63a0ca;
  --bolt-core:  #e8f6ff;
  --bolt-glow:  #63a0ca;
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
}

/* iOS vergrößert Text sonst von selbst, sobald das Gerät gedreht wird. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  /* Handy: kein Mitziehen/Gummiband der Seite, kein Doppeltipp-Zoom, kein
     Textmarkieren durch langes Drücken. */
  overscroll-behavior: none;
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
}

[hidden] { display: none !important; }

/* Vollflächig, Logo in der Mitte. 100dvh, damit die Adressleiste von
   Smartphones den Inhalt nicht aus der Mitte schiebt. */
.stage {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: var(--bg);
}

/* --- Ladebildschirm: Fake-Ladebalken, bis das Intro per Klick startet --- */
.loader {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  transition: opacity 0.7s ease, visibility 0s linear 0.7s;
}
.stage:not(.is-waiting) .loader {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
/* Fortschrittsanzeige und Button teilen sich dieselbe Stelle (ein
   Gitterfeld): erst blendet die Anzeige aus, dann der Button ein. */
/* Beim Öffnen der Seite ist zuerst nur der dunkle Hintergrund da; der
   Ladebildschirm erscheint 0,7 s später (js/intro.js, LOADER_START_DELAY_MS)
   und blendet dabei weich ein (.is-visible). */
.loader-box {
  opacity: 0;
  transition: opacity 0.4s ease;
}
.loader-box.is-visible { opacity: 1; }
.loader-box {
  width: min(340px, 78vw);
  display: grid;
  font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
}
.loader-progress,
.loader-enter { grid-area: 1 / 1; }
.loader-progress {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  transition: opacity 0.6s ease;
}
.loader-box.is-complete .loader-progress { opacity: 0; }
.loader-percent {
  align-self: center;
  text-align: center;
  margin-bottom: 8px;
  font-size: 12px;
  letter-spacing: 0.12em;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
/* Kein overflow:hidden - das Leuchten an der Spitze soll über den Balken
   hinausragen dürfen. */
.loader-track {
  height: 4px;
  border-radius: 2px;
  background: #161c28;
}
.loader-fill {
  position: relative;
  width: 0;
  height: 100%;
  border-radius: 2px;
  background: linear-gradient(90deg, #316a91, var(--accent), #9fd4ff);
}
/* Leichtes blaues Leuchten an der Spitze des Balkens: ein weicher
   Lichtpunkt, der mit der Spitze mitwandert (sitzt am rechten Ende der
   Füllung) und leise atmet. */
.loader-fill::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 0;
  width: 26px;
  height: 26px;
  margin: -13px -13px 0 0;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(159, 212, 255, 0.85) 0%, rgba(99, 160, 202, 0.4) 35%, rgba(99, 160, 202, 0) 70%);
  pointer-events: none;
  animation: loader-tip-glow 1.4s ease-in-out infinite;
}
@keyframes loader-tip-glow {
  0%, 100% { opacity: 0.65; }
  50%      { opacity: 1; }
}
/* Bei 100 % (js/intro.js setzt .is-full) hört die Spitze auf zu leuchten:
   Sie blendet in einer halben Sekunde aus und bleibt dann aus. */
.loader-fill.is-full::after {
  animation: loader-tip-off 0.5s ease-out forwards;
}
@keyframes loader-tip-off {
  from { opacity: 0.85; }
  to   { opacity: 0; }
}
.loader-status {
  margin: 12px 0 0;
  text-align: center;
  font-size: 11px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-faint);
  /* Beide Texte liegen im selben Gitterfeld übereinander. Die Abfolge
     steuert js/intro.js über zwei Klassen: .is-fading blendet "Accessing
     Data" aus, 0,5 s später blendet .is-done "Done" ein - dazwischen
     ist die Zeile leer (LOADER_GAP_MS in js/intro.js). */
  display: grid;
  justify-items: center;
}
.loader-status-text {
  grid-area: 1 / 1;
  transition: opacity 0.6s ease, color 0.6s ease;
}
.loader-status-done {
  opacity: 0;
  color: var(--accent);
}
.loader-status.is-fading .loader-status-working { opacity: 0; }
.loader-status.is-done .loader-status-done      { opacity: 1; }
.loader-enter {
  align-self: center;
  justify-self: center;
  padding: 11px 34px;
  font: inherit;
  font-size: 13px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--accent);
  background: rgba(99, 160, 202, 0.08);
  border: 1px solid var(--accent);
  border-radius: 6px;
  cursor: pointer;
  box-shadow: 0 0 18px rgba(99, 160, 202, 0.25);
  /* Platz ist von Anfang an reserviert (sonst rutscht der Balken nach oben);
     sichtbar und bedienbar erst nach "Done" (.is-ready). */
  visibility: hidden;
  transition: background 0.3s ease, box-shadow 0.3s ease, color 0.3s ease,
              border-color 0.3s ease, text-shadow 0.3s ease, scale 0.3s ease;
}
.loader-enter.is-ready {
  visibility: visible;
  animation: loader-enter-in 0.6s ease-out both;
}
/* Mouseover (und Tastaturfokus): Der Button wird hervorgehoben - er wächst
   leicht, Rahmen und Schrift werden heller, und das Blau beginnt weich zu
   leuchten (Lichthof außen und innen, dazu ein langsames Atmen).
   "scale" statt "transform", weil die Einblend-Animation (fill-mode both)
   den transform-Wert festhält. */
.loader-enter:focus-visible {
  scale: 1.07;
  color: #fff;
  border-color: #9fd4ff;
  background: rgba(99, 160, 202, 0.2);
  text-shadow: 0 0 10px rgba(159, 212, 255, 0.9);
  box-shadow:
    0 0 14px rgba(99, 160, 202, 0.55),
    0 0 36px rgba(99, 160, 202, 0.4),
    inset 0 0 14px rgba(99, 160, 202, 0.3);
  outline: none;
  animation: loader-enter-in 0.6s ease-out both, loader-enter-glow 1.8s ease-in-out 0.3s infinite;
}
/* Mouseover nur auf Geräten mit echter Maus (hover: hover). Auf dem Handy
   bliebe :hover nach dem Tippen sonst hängen und der Button leuchtete
   weiter. */
@media (hover: hover) {
  .loader-enter:hover {
    scale: 1.07;
    color: #fff;
    border-color: #9fd4ff;
    background: rgba(99, 160, 202, 0.2);
    text-shadow: 0 0 10px rgba(159, 212, 255, 0.9);
    box-shadow:
      0 0 14px rgba(99, 160, 202, 0.55),
      0 0 36px rgba(99, 160, 202, 0.4),
      inset 0 0 14px rgba(99, 160, 202, 0.3);
    outline: none;
    animation: loader-enter-in 0.6s ease-out both, loader-enter-glow 1.8s ease-in-out 0.3s infinite;
  }
}
.loader-enter:active { scale: 1.02; }

/* Nach dem Klick gleitet der Button nach unten aus dem Bild; erst danach
   erscheint das Logo (js/intro.js, startIntro). "translate" statt
   "transform", weil die Einblend-Animation transform festhält. Die Dauer
   (0,7 s) muss zu LOADER_LEAVE_MS in js/intro.js passen. Die Bewegung
   beschleunigt zum Ende hin, als würde der Button herunterfallen. */
.loader-enter.is-leaving {
  /* Mitte des Buttons liegt auf halber Höhe: 50 % bis zum Rand plus 100 px
     schiebt ihn auf jedem Gerät vollständig unter den Bildrand. */
  translate: 0 calc(50vh + 100px);
  translate: 0 calc(50dvh + 100px);
  pointer-events: none;
  transition: translate 0.7s cubic-bezier(0.55, 0, 0.9, 0.45);
}
@keyframes loader-enter-glow {
  0%, 100% {
    box-shadow:
      0 0 14px rgba(99, 160, 202, 0.55),
      0 0 36px rgba(99, 160, 202, 0.4),
      inset 0 0 14px rgba(99, 160, 202, 0.3);
  }
  50% {
    box-shadow:
      0 0 20px rgba(130, 190, 235, 0.75),
      0 0 52px rgba(99, 160, 202, 0.55),
      inset 0 0 18px rgba(130, 190, 235, 0.4);
  }
}
@keyframes loader-enter-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Bis zum Klick auf "Enter" ruht das Intro: Logo und Blitze sind
   verborgen, damit nichts davon vorab sichtbar ist. */
.stage.is-waiting .splash,
.stage.is-waiting .bolts { visibility: hidden; }

/* --- Logo: dreht sich räumlich um die senkrechte Achse (wie eine Münze).
   Die Perspektive am Button lässt die nähere Seite größer wirken. --- */
.splash {
  position: relative;
  z-index: 1;
  padding: 0;
  border: 0;
  background: none;
  border-radius: 50%;
  cursor: pointer;
  perspective: 1100px;
  transition: transform 0.25s ease;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) {
  .splash:hover { transform: scale(1.06); }
}
.splash:focus-visible { outline: 2px solid var(--accent); outline-offset: 12px; }

.splash-logo {
  display: block;
  /* Höchstens 60 % der Breite UND 38 % der Höhe: Im Querformat am Handy
     bliebe sonst zu wenig Platz für den Schriftzug darunter. */
  width: min(320px, 60vw, 38vh);
  height: auto;
  /* Kein Bildmenü / Ziehen beim langen Drücken auf dem Handy. */
  -webkit-touch-callout: none;
  -webkit-user-drag: none;
  pointer-events: none;
  animation: logo-turn 9s linear infinite;
  /* Eigene Ebene für die Grafikkarte: Die Drehung läuft flüssig weiter,
     auch wenn daneben Blitze und Text neu gezeichnet werden. */
  will-change: transform;
  /* Unsichtbar, bis das Bild geladen ist - dann blendet es weich ein. */
  opacity: 0;
}
.splash-logo.is-loaded {
  opacity: 1;
  animation: logo-turn 9s linear infinite, logo-in 2s ease-out;
}
@keyframes logo-turn {
  from { transform: rotateY(0deg); }
  to   { transform: rotateY(360deg); }
}
/* Pulsieren: Sobald die Musik-Schleife läuft, schwillt das Logo bei jedem
   Blitz zweimal kurz an (ein Schlag der Musik = 0,67 s). Animiert wird
   "scale", nicht "transform", damit die Drehung ungestört weiterläuft. */
.splash.is-pulsing .splash-logo.is-loaded {
  animation: logo-turn 9s linear infinite, logo-in 2s ease-out, logo-pulse 1.34s ease-in-out;
}
@keyframes logo-pulse {
  0%, 50%, 100% { scale: 1; }
  25%, 75%      { scale: 1.16; }
}
@keyframes logo-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* --- Schriftzüge unter dem Logo: einblenden, stehen, ausblenden.
   Den Takt gibt js/intro.js vor (setzt .is-showing). --- */
.splash-hint {
  position: absolute;
  left: 50%;
  top: calc(100% + 18px);
  transform: translateX(-50%);
  width: max-content;
  max-width: 90vw;
  text-align: center;
  text-wrap: balance;
  line-height: 1.5;
  font-size: 18px;
  font-weight: 500;
  letter-spacing: 0.32em;
  color: var(--accent);
  text-shadow: 0 0 18px rgba(99, 160, 202, 0.55);
  opacity: 0;
  pointer-events: none;
  will-change: opacity, transform;
}
/* Ein Durchlauf: 1,5 s ein, 3 s stehen, 1,5 s aus. Dauer = Abstand
   der Blitze (LIGHTNING_INTERVAL_MS in js/intro.js), damit ein Satz genau
   ausblendet, wenn der nächste erscheint. */
.splash-hint.is-showing { animation: hint-pulse 6s ease-in-out both; }
@keyframes hint-pulse {
  0%   { opacity: 0; transform: translateX(-50%) translateY(10px); }
  25%  { opacity: 1; transform: translateX(-50%) translateY(0); }
  75%  { opacity: 1; transform: translateX(-50%) translateY(0); }
  100% { opacity: 0; transform: translateX(-50%) translateY(-6px); }
}

/* --- Blitze: js/intro.js zeichnet die Linien in dieses SVG. Die Dauer
   (0,8 s) muss zu LIGHTNING_VISIBLE_MS in js/intro.js passen. --- */
.bolts {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
  /* Leistung: einmal zeichnen, danach nur die Deckkraft der ganzen Fläche
     ändern (macht die Grafikkarte). Das Leuchten entsteht aus breiteren,
     durchscheinenden Linien unter dem hellen Kern. */
  opacity: 0;
  will-change: opacity;
}
.bolts.is-flashing { animation: bolt-flash 0.8s ease-out forwards; }
.bolt {
  fill: none;
  stroke: var(--bolt-core);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.bolt.is-branch { stroke-width: 1.3; }
.bolt-glow { stroke: var(--bolt-glow); stroke-width: 7; stroke-opacity: 0.32; }
.bolt-glow.is-wide { stroke-width: 16; stroke-opacity: 0.13; }
.bolt-glow.is-branch { stroke-width: 4.5; }
@keyframes bolt-flash {
  0%   { opacity: 0; }
  5%   { opacity: 1; }
  12%  { opacity: 1; }
  22%  { opacity: 0.3; }
  30%  { opacity: 1; }
  45%  { opacity: 0.55; }
  55%  { opacity: 0.9; }
  100% { opacity: 0; }
}

/* Lichthof hinter dem Logo: nur die Deckkraft wird animiert. */
.splash-glow {
  position: absolute;
  inset: -35%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(159, 212, 255, 0.5) 0%, rgba(99, 160, 202, 0.22) 35%, transparent 68%);
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
}
.splash.is-struck .splash-glow { animation: bolt-flash 0.8s ease-out; }

/* --- Fußzeile --- */
.stage-footer {
  position: absolute;
  left: 0;
  right: 0;
  /* Auf Handys mit Notch bzw. Home-Balken (viewport-fit=cover) nicht
     darunter rutschen. */
  bottom: max(16px, env(safe-area-inset-bottom));
  padding: 0 max(16px, env(safe-area-inset-left)) 0 max(16px, env(safe-area-inset-right));
  text-align: center;
  font-size: 12px;
  color: var(--text-faint);
}

/* Das Intro läuft bewusst IMMER animiert - auch bei "Bewegung reduzieren".
   Diese Meldung kommt nicht nur von Menschen, sondern auch automatisch,
   wenn Windows die Animationen abgeschaltet hat (Fernwartung,
   "Für optimale Leistung anpassen"). Dort stünde das Logo sonst still. */

/* --- Handy --- */

/* Hochkant: kleinere Schrift, Button mit großer Tippfläche (mind. 44 px
   hoch, wie von iOS/Android empfohlen). */
@media (max-width: 480px) {
  .splash-hint { font-size: 14px; letter-spacing: 0.2em; }
  .loader-enter { padding: 15px 44px; font-size: 14px; }
  .loader-percent { font-size: 11px; }
}

/* Sehr schmale Geräte (z. B. 320 px): Schrift noch etwas kleiner, damit
   "Website under construction" in zwei Zeilen statt über den Rand läuft. */
@media (max-width: 360px) {
  .splash-hint { font-size: 12.5px; letter-spacing: 0.16em; }
}

/* Querformat am Handy (wenig Höhe): Schriftzug dichter ans Logo, kleinerer
   Abstand zur Fußzeile, kompakter Loader. */
@media (max-height: 480px) and (orientation: landscape) {
  .splash-hint { top: calc(100% + 8px); font-size: 13px; letter-spacing: 0.2em; }
  .stage-footer { font-size: 11px; bottom: max(8px, env(safe-area-inset-bottom)); }
  .loader-enter { padding: 12px 40px; }
}
