/* ==========================================================================
   Animationen
   Dauern kommen aus tokens.css und stehen bei prefers-reduced-motion auf 0.
   ========================================================================== */

/* Menü-Overlay: Bewegung in motion.js (fdpMotion.menu), Zustände in components.css */

/* ---------- Einblend-Effekte: [data-animate] (Logik in animations.js) ----------
   Versteckte Startzustände nur mit JS (.js) und ohne reduced-motion.
   Bewegt werden ausschliesslich translate/scale und opacity; Reveals nutzen clip-path. */

.split-word {
  display: inline-block;
}

.split-word--mask {
  /* Maske für einlaufende Buchstaben/Wörter; Luft für Unterlängen */
  overflow: clip;
  padding-bottom: 0.2em;    /* Unterlängen (g, j, p) reichen bei enger Zeilenhöhe bis 0.22em unter die Grundlinie */
  margin-bottom: -0.2em;
  vertical-align: top;
}

.split-char {
  display: inline-block;
}

@media (prefers-reduced-motion: no-preference) {
  /* fade-up */
  .js [data-animate="fade-up"] {
    opacity: 0;
    translate: 0 2.5rem;
    transition: opacity var(--dur-slower) var(--ease-out-expo) var(--delay, 0ms),
                translate var(--dur-slower) var(--ease-out-expo) var(--delay, 0ms);
  }

  /* stagger: Kinder nacheinander */
  .js [data-animate="stagger"] > * {
    opacity: 0;
    translate: 0 2.5rem;
    transition: opacity var(--dur-slower) var(--ease-out-expo),
                translate var(--dur-slower) var(--ease-out-expo);
    transition-delay: calc(var(--delay, 0ms) + var(--i, 0) * 90ms);
  }

  .js [data-animate="fade-up"].is-in,
  .js [data-animate="stagger"].is-in > * {
    opacity: 1;
    translate: 0 0;
  }

  /* reveal: von unten aufdecken, Bild setzt sich dabei leicht */
  .js [data-animate="reveal"] {
    clip-path: inset(100% 0 0 0);
    transition: clip-path var(--dur-slower) var(--ease-out-expo) var(--delay, 0ms);
  }

  .js [data-animate="reveal"] img {
    scale: 1.15;
    transition: scale calc(var(--dur-slower) * 1.4) var(--ease-out-expo) var(--delay, 0ms);
  }

  .js [data-animate="reveal"].is-in {
    clip-path: inset(0 0 0 0);
  }

  .js [data-animate="reveal"].is-in img {
    scale: 1;
  }

  .hero__scroll-line::after {
    animation: scroll-hint 2.4s var(--ease-in-out) infinite;
  }

  /* Schwerpunkt-Icon zeichnet sich beim Hover nach (Formen im Sprite haben pathLength="1") */
  .focus-item:hover .focus-item__icon,
  .focus-item:has(.focus-item__link:focus-visible) .focus-item__icon {
    stroke-dasharray: 1;
    animation: icon-draw 600ms var(--ease-out-expo) both;
  }
}

@keyframes icon-draw {
  from { stroke-dashoffset: 1; }
  to   { stroke-dashoffset: 0; }
}

@keyframes rise-in {
  from { opacity: 0; translate: 0 1.5rem; }
  to   { opacity: 1; translate: 0 0; }
}

@keyframes scroll-hint {
  0%        { translate: 0 -100%; }
  45%, 55%  { translate: 0 0; }
  100%      { translate: 0 100%; }
}

/* ---------- Bewegungs-System: [data-motion] (Logik in motion.js) ----------
   Hier stehen nur die versteckten Startzustände, damit vor dem Start nichts aufblitzt.
   Sie gelten nur mit JS, ohne reduced-motion und ohne .motion-static (GSAP fehlt oder
   motion.js hat nach 4 s nicht gestartet). Die Bewegung selbst macht GSAP. */

[data-motion~="count"] {
  font-variant-numeric: tabular-nums;   /* Ziffern springen beim Zählen nicht hin und her */
}

@media (prefers-reduced-motion: no-preference) {
  /* split: verborgen, bis motion.js den Text zerlegt und unter die Maske geschoben hat */
  .js:not(.motion-static) [data-motion~="split"]:not([data-split-done]) {
    visibility: hidden;
  }

  /* pop: verborgen, bis GSAP übernimmt (.is-in setzt motion.js beim Start) */
  .js:not(.motion-static) [data-motion~="pop"]:not(.is-in) {
    visibility: hidden;
  }

  /* draw: Linien noch nicht gezeichnet (Formen haben pathLength="1") */
  .js:not(.motion-static) [data-motion~="draw"]:not(.is-in) {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
  }

  /* tag: schräge Wischkante. GSAP zählt --wipe von 0 auf 1; die Oberkante läuft der Unterkante voraus.
     Zeilen (__main/__sub) einzeln, einzelne Balken (--hashtag, --stamp, --sub) als Ganzes. */
  .js:not(.motion-static) [data-motion~="tag"] > :is(.campaign-tag__main, .campaign-tag__sub),
  .js:not(.motion-static) [data-motion~="tag"]:not(:has(> .campaign-tag__main, > .campaign-tag__sub)) {
    --wipe: 0;
    clip-path: polygon(
      -1em -1em,
      calc(var(--wipe) * (100% + 3em) - 1em) -1em,
      calc(var(--wipe) * (100% + 3em) - 2em) calc(100% + 1em),
      -1em calc(100% + 1em)
    );
  }
}

/* ---------- Wörter färben sich beim Scrollen ein [data-scroll-words] ----------
   Ohne JS und bei reduced-motion bleibt der Text schwarz. */

.is-scroll-words .split-word {
  color: var(--color-gray-400);
  transition: color var(--dur-base) var(--ease-out-expo);
}

.is-scroll-words .split-word.is-on {
  color: var(--color-text);
}

/* ---------- Eigener Cursor (nur Desktop mit Maus, animations.js) ----------
   Die Grösse ändert sich nur per scale, die Beschriftung nur per opacity. */

.has-cursor,
.has-cursor * {
  cursor: none;
}

.has-cursor :is(input:not([type="radio"]):not([type="checkbox"]), textarea, select) {
  cursor: text;
}

/* Overlays (Person, Artikel) liegen als <dialog> in der obersten Browser-Ebene, über dem eigenen Cursor.
   Dort gilt deshalb der normale Mauszeiger; animations.js blendet den eigenen Cursor über Dialogen aus. */
.has-cursor dialog,
.has-cursor dialog *,
.has-cursor dialog::backdrop {
  cursor: auto;
}

.has-cursor dialog :is(a, button, summary, label, [role="button"]),
.has-cursor dialog :is(a, button, summary, label, [role="button"]) * {
  cursor: pointer;
}

.cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 3000;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-fast) linear;
}

.cursor.is-visible {
  opacity: 1;
}

.cursor__dot,
.cursor__label {
  position: absolute;
  top: -2.5rem;
  left: -2.5rem;
  width: 5rem;
  height: 5rem;
  border-radius: var(--radius-pill);
}

.cursor__dot {
  background: var(--color-blue);
  box-shadow: 0 0 0 1px rgb(255 255 255 / 0.9);
  scale: 0.12;
  transition: scale var(--dur-base) var(--ease-out-expo), background-color var(--dur-fast) linear;
}

.cursor__label {
  display: grid;
  place-items: center;
  color: var(--color-white);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.04em;
  opacity: 0;
  transition: opacity var(--dur-fast) linear;
}

.cursor[data-mode="link"] .cursor__dot { scale: 0.55; }
.cursor[data-mode="label"] .cursor__dot { scale: 1; }
.cursor[data-mode="hidden"] { opacity: 0; }

.cursor[data-mode="link"] .cursor__label,
.cursor[data-mode="label"] .cursor__label {
  opacity: 1;
}

.cursor[data-mode="link"] .cursor__label {
  font-size: var(--text-lg);
}

.cursor.is-pressed .cursor__dot {
  scale: 0.1;
}

.cursor.is-pressed[data-mode] .cursor__dot {
  scale: 0.45;
}

.cursor.is-on-dark .cursor__dot {
  background: var(--color-white);
  box-shadow: 0 0 0 1px rgb(56 81 145 / 0.6);
}

.cursor.is-on-dark .cursor__label {
  color: var(--color-blue);
}

/* ---------- Lenis (sanftes Scrollen) ----------
   Regeln aus lenis.css 1.3.26, damit keine zusätzliche Datei geladen werden muss. */

html.lenis,
html.lenis body {
  height: auto;
}

.lenis.lenis-smooth {
  scroll-behavior: auto !important;
}

.lenis:not(.lenis-autoToggle).lenis-stopped {
  overflow: clip;
}

.lenis [data-lenis-prevent] {
  overscroll-behavior: contain;
}

.lenis.lenis-smooth iframe {
  pointer-events: none;
}

/* ---------- Laufbänder: nahtlose CSS-Schleife ----------
   Zwei identische Gruppen; die Spur wandert um genau eine Gruppenbreite (-50 %). */

@media (prefers-reduced-motion: no-preference) {
  .marquee__track {
    animation: marquee var(--marquee-duration, 45s) linear infinite;
  }

  .marquee--reverse .marquee__track {
    animation-direction: reverse;
  }

  .marquee:hover .marquee__track,
  .marquee:focus-within .marquee__track,
  .marquees.is-paused .marquee__track {
    animation-play-state: paused;
  }

  .js .marquees__toggle {
    display: inline-block;
  }
}

@keyframes marquee {
  to { translate: -50% 0; }
}

/* Reduzierte Bewegung: statische Liste statt Laufband */
@media (prefers-reduced-motion: reduce) {
  .marquee__track {
    width: auto;
    padding-inline: var(--gutter);
  }

  .marquee__group {
    flex-wrap: wrap;
    row-gap: var(--space-2);
  }

  .marquee__group[aria-hidden="true"] {
    display: none;
  }

  .marquee--values li:last-child::after {
    display: none;
  }

  .marquee--quotes .marquee__group {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
  }

  .marquee--quotes li::after {
    display: none;
  }

  .marquee--quotes figure {
    flex-wrap: wrap;
    white-space: normal;
  }
}

/* ---------- Seitenübergänge ----------
   Ein blaues Panel schiebt sich von unten ins Bild, deckt die alte Seite ab
   und gibt die neue nach oben frei.
   1. Browser mit Cross-Document View Transitions: reines CSS (unten).
   2. Andere Browser: animations.js steuert .page-curtain über Klassen.
   Bei reduzierter Bewegung nur ein kurzer Fade. */

@view-transition {
  navigation: auto;
}

.page-curtain {
  position: fixed;
  inset: 0;
  z-index: var(--z-curtain);
  background: var(--color-blue);
  translate: 0 100%;
  pointer-events: none;
  view-transition-name: page-curtain;
}

/* 1. View Transitions API */

::view-transition-group(page-curtain) {
  animation: curtain-sweep 1000ms var(--ease-in-out) both;
}

::view-transition-old(page-curtain) {
  display: none;
}

::view-transition-new(page-curtain) {
  animation: none;
}

::view-transition-old(root) {
  animation: page-out 1000ms step-end both;
}

::view-transition-new(root) {
  animation: page-in 1000ms var(--ease-out-expo) both;
}

@keyframes curtain-sweep {
  0%       { transform: translateY(100vh); }
  45%, 55% { transform: translateY(0); }
  100%     { transform: translateY(-100vh); }
}

@keyframes page-out {
  0%   { opacity: 1; }
  50%  { opacity: 0; }
}

@keyframes page-in {
  0%, 50% { opacity: 0; transform: translateY(3rem); }
  51%     { opacity: 1; }
  100%    { opacity: 1; transform: none; }
}

/* 2. Fallback ohne View Transitions (Klassen setzt animations.js / Inline-Script im <head>) */

.is-leaving .page-curtain {
  translate: 0 0;
  transition: translate 500ms var(--ease-in-out);
}

.is-arriving .page-curtain {
  translate: 0 0;
}

.is-revealing .page-curtain {
  translate: 0 -100%;
  transition: translate 600ms var(--ease-in-out);
}

/* Reduzierte Bewegung: kein Panel, nur ein kurzer Fade (bewusst feste 180ms,
   die Dauer-Tokens stehen hier auf 0) */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(page-curtain) {
    animation: none;
  }

  ::view-transition-old(root) {
    animation: fade-out 180ms linear both;
  }

  ::view-transition-new(root) {
    animation: fade-in 180ms linear both;
  }

  .page-curtain,
  .is-leaving .page-curtain,
  .is-arriving .page-curtain,
  .is-revealing .page-curtain {
    translate: 0 100%;
  }

  html.is-leaving body {
    opacity: 0;
    transition: opacity 150ms linear !important;
  }

  html.is-arriving body {
    animation: fade-in 180ms linear both !important;
  }
}

@keyframes fade-out {
  to { opacity: 0; }
}

@keyframes fade-in {
  from { opacity: 0; }
}
