/* =========================================================
   RAGETTLI CREATION — About page styles
   =========================================================
   All colors, fonts and spacing live in :root below.
   Values were measured from the original design
   (ragettli-creation.ch/about) with browser DevTools.
   ========================================================= */

/* The two brand typefaces, both self-hosted from assets/.
   NIKEA is caps-only and carries the big headings; Lato does everything else.
   See the licensing note in README.md. */
@font-face {
  font-family: "NIKEA Regular";
  src: url("assets/NIKEA.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  /* War `optional`: die Schrift wird geladen oder auch nicht, je nach
     Zeitpunkt — und weil NIKEA und die serifenlose Ausweichschrift
     unterschiedlich breit setzen, sprang bei jedem Wechsel der Zeilenumbruch
     mit, in der langen deutschen Überschrift sichtbarer als in der kurzen
     englischen. `block` blendet stattdessen kurz nichts ein, bis die Schrift
     da ist (sie ist oben als preload verdrahtet, also fast immer rechtzeitig)
     — das Ergebnis ist ein einziges, stilles Erscheinen statt eines
     Wechsels mitten im Satz. */
  font-display: block;
}

@font-face {
  font-family: "Lato";
  src: url("assets/Lato-Light.woff2") format("woff2");
  font-weight: 300;
  font-style: normal;
  font-display: optional;
}

@font-face {
  font-family: "Lato";
  src: url("assets/Lato-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: optional;
}

@font-face {
  font-family: "Lato";
  src: url("assets/Lato-Italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: optional;
}

@font-face {
  font-family: "Lato";
  src: url("assets/Lato-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: optional;
}

@font-face {
  font-family: "Lato";
  src: url("assets/Lato-BoldItalic.woff2") format("woff2");
  font-weight: 700;
  font-style: italic;
  font-display: optional;
}

/* Die Schriften laden mit font-display: optional statt swap. Mit swap
   zeichnete der Browser beim Seitenwechsel erst die Systemschrift und tauschte
   sie eine Zehntelsekunde später aus — die Navigation sprang sichtbar um.
   Zusammen mit dem <link rel="preload"> in jedem <head> ist die Datei fast
   immer schon da, und wenn nicht, bleibt es bei der Ersatzschrift, ohne Sprung.
   Outfit stands in for Action Sans, which the brandbook wants on titles and
   subtitles but which we have no licence for. Same geometric skeleton — round
   bowls, horizontal terminals, two-storey a. One variable file covers 100-900,
   so asking for any weight costs no extra request. */
@font-face {
  font-family: "Outfit";
  src: url("assets/Outfit.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: optional;
}

:root {
  /* --- Palette (measured from the original) --- */
  --bg: #0e0f11;            /* page + footer background */
  --ink: #ffffff;           /* headings, names, nav */
  --ink-soft: #8a8f8d;      /* paragraph text (original: #666, lifted slightly for AA contrast) */
  --accent: #89b8ae;        /* sage green — eyebrow text, logo triangle */
  --accent-light: #a8dacf;  /* lighter sage — hero highlight word, primary buttons */
  --pill-bg: rgba(0, 0, 0, 0.3);   /* nav + language pills */
  --card-bg: rgba(0, 0, 0, 0.2);   /* vision/mission cards */
  --line: rgba(255, 255, 255, 0.12);
  --btn-bg: #ffffff;        /* primary button */
  --btn-ink: #0e0f11;

  /* --- Typography (the brand typefaces, per the brandbook) --- */
  --font-display: "NIKEA Regular", sans-serif;   /* big caps headings */
  --font-title: "Outfit", system-ui, sans-serif; /* card + team titles, testimonials */
  --font-body: "Lato", system-ui, sans-serif;    /* body copy — 16px on the live site */
  /* Outfit, not Lato, for the interface. The original ran Geist here — a
     geometric grotesque — and Lato is humanist, which is why the nav and the
     buttons kept reading as "some other site" whatever size they were set at. */
  --font-ui: "Outfit", system-ui, sans-serif;    /* nav, buttons, small labels */

  /* --- Layout --- */
  /* 1280 outer minus the 30px gutters below = 1220px of content, which is
     what the live site lays out against (measured at 1280px viewport). */
  --container: 1280px;
  --radius: 24px;
  --header-h: 114px;
  --section-pad: 96px;
}

/* ---------- Reset & base ---------- */
*, *::before, *::after { box-sizing: border-box; }
/* Zieht man im Opener nach unten, schob das Gummiband einen schwarzen
   Streifen über das Video. Die Seite endet jetzt am Rand. */
html { overscroll-behavior-y: none; }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 16px;          /* live site: Inter 16px */
  line-height: 1.6;         /* 25.6px */
  letter-spacing: -0.4px;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { margin: 0; padding: 0; list-style: none; }

.container { max-width: var(--container); margin: 0 auto; padding: 0 30px; }

/* Heading scale measured off the live site at 960 / 1280 / 1600px:
   h1 = 48 / 56 / 64px  ->  24px + 2.5vw
   h2 = 36 / 42 / 48px  ->  18px + 1.875vw
   Both track the viewport linearly; the clamps only guard the extremes. */
h1, h2 {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  line-height: 1.2;
  letter-spacing: normal;
  margin: 0 0 0.6em;
  color: var(--ink);
}
h3, h4 { font-family: var(--font-title); font-weight: 600; margin: 0 0 0.4em; color: var(--ink); }
.h2 { font-size: clamp(30px, calc(18px + 1.875vw), 60px); line-height: 1.2; }
p { margin: 0 0 1em; color: var(--ink-soft); }
p:last-child { margin-bottom: 0; }

.eyebrow {
  font-size: 13px;
  color: var(--accent);
  margin-bottom: 10px;
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  clip: rect(0 0 0 0); overflow: hidden; white-space: nowrap;
}

/* ---------- Header / nav ----------
   Measured from the live site (Aug 2026): the dark blur is a FULL-BLEED
   strip across the viewport (no rounding, no max-width). The only rounded
   element is the frosted pill around the menu itself — see .main-nav. */
/* The header bar itself stays transparent so the hero video reaches the top of
   the viewport. The glass is a floating panel inside it, set to the same 1220px
   the page content uses, so its edges line up with the three testimonial cards
   and the case-study grid rather than running to the window edge. */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  padding-bottom: 15px;
}
.nav-inner {
  position: relative;
  width: min(1220px, 100% - 32px);
  margin: 14px auto 0;
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  padding: 19px 16px;
  /* Darker and blurrier than the pill it contains. Two layers of backdrop
     blur is what gives the stacked-glass look: the panel frosts the page,
     the pill frosts the panel again. */
  background: rgba(10, 11, 12, 0.42);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 18px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.28);
}
/* object-fit: cover is load-bearing, not decoration. The logo SVG's viewBox
   is 340x156 (aspect 2.18) but this box is 150x38 (aspect 3.95), and the
   wordmark ink sits in the middle band of that tall canvas. Without `cover`
   the SVG letterboxes to fit the height and the wordmark draws only ~83px
   wide — a 45% smaller logo. `cover` scales to the width and crops the
   empty margin, which is what the live site does. */
.logo img { width: 150px; height: 38px; object-fit: cover; }

/* Frosted "glass pill" — from the original design:
   1px white border, blur(10px), and an inset 81px white glow
   instead of a dark background. */
.main-nav {
  display: flex; gap: 8px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07) 0%, rgba(255, 255, 255, 0.035) 100%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 0 14px 0 rgba(255, 255, 255, 0.06), inset 0 0 42px 0 rgba(255, 255, 255, 0.10);
  border-radius: 12px;
  padding: 5px;
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
}
.main-nav a {
  /* The original runs Geist at 13px, but Lato sets smaller at any given size
     and the pill has room to spare, so the nav is deliberately a touch larger
     than the measurement rather than faithful to it. */
  font-family: var(--font-ui);
  font-size: 17.5px; color: var(--ink);
  line-height: 1.5em; letter-spacing: normal;
  padding: 10px 19px; border-radius: 10px;
  transition: background .2s;
}
.main-nav a:hover { background: rgba(255, 255, 255, 0.08); }

.nav-right { display: flex; align-items: center; gap: 12px; }
.lang-select {
  display: flex; align-items: center; gap: 5px;
  height: 53px; box-sizing: border-box;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07) 0%, rgba(255, 255, 255, 0.035) 100%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 0 14px 0 rgba(255, 255, 255, 0.06), inset 0 0 42px 0 rgba(255, 255, 255, 0.10);
  border-radius: 12px;
  padding: 0 15px;
}
.lang-select svg { color: var(--ink); }
.lang-select select {
  font-family: var(--font-body);
  font-size: 16px; line-height: 1.5em; color: var(--ink);
  background: transparent; border: 0; cursor: pointer;
  appearance: none; -webkit-appearance: none;
  padding-right: 2px;
}
.lang-select select option { color: #000; }

.nav-toggle { display: none; background: var(--pill-bg); border: 0; border-radius: 12px; cursor: pointer; padding: 12px 10px; }
.nav-toggle span {
  display: block; width: 22px; height: 2px; background: var(--ink);
  margin: 5px 0; transition: transform .2s, opacity .2s;
}

/* ---------- Story (hero) ---------- */
.story { padding-top: calc(var(--header-h) + 86px); }
.story-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(48px, 9vw, 127px);
  align-items: start;
}
.story-portrait { margin: 0; border-radius: 12px; overflow: hidden; }
.story-portrait img { width: 100%; aspect-ratio: 549 / 582; object-fit: cover; object-position: 50% 14%; }
.story-text a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.story-text a:hover { color: var(--accent); }
.story-stats { margin-top: 28px; width: 171px; }

/* ---------- Vision & mission ---------- */
.vision-mission { padding: var(--section-pad) 0; }
.vm-grid {
  display: grid; grid-template-columns: 1.1fr 1fr;
  gap: clamp(32px, 5vw, 61px);
  align-items: center;
}
/* Left: portrait sitting on a photographic card with a soft sage wash */
.vm-media {
  margin: 0; position: relative;
  border-radius: 30px; overflow: hidden;
  aspect-ratio: 610 / 602;
  display: grid; place-items: center;
}
.vm-media-bg {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
}
/* Das Bild hinter dem Porträt ist ein fast schwarzer Verlauf. Farbmischungen
   greifen darauf nicht — multiplizieren lässt Schwarz schwarz. Deshalb liegt
   hier ein Salbei-Verlauf direkt darüber: oben satt, nach unten auslaufend,
   damit das Porträt sauber davor steht. */
.vm-media::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(155deg,
      rgba(137, 184, 174, .62) 0%,
      rgba(137, 184, 174, .34) 48%,
      rgba(137, 184, 174, .12) 76%,
      rgba(14, 15, 17, .42) 100%);
}
.vm-portrait { z-index: 2; }
.vm-portrait {
  position: relative; z-index: 1;
  width: 76%; aspect-ratio: 1 / 1; object-fit: cover;
  border-radius: var(--radius);
}
/* Right: two stacked cards */
.vm-cards { display: flex; flex-direction: column; gap: 24px; }
.vm-card {
  background: var(--card-bg);
  border-radius: var(--radius);
  padding: 24px;
  display: flex; flex-direction: column; gap: 16px;
}
.vm-card p, .vm-card h3 { margin: 0; }
.vm-icon { width: 40px; height: 40px; }
.vm-card h3 { font-size: 26px; }

/* ---------- Team carousel ---------- */
.team { padding-bottom: var(--section-pad); }
.team-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 24px; margin-bottom: 40px;
}
.team-head .h2 { margin-bottom: 0; }
.team-track {
  display: flex; gap: 24px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding-bottom: 8px;
  scrollbar-width: none;
}
.team-track::-webkit-scrollbar { display: none; }
.team-card {
  flex: 0 0 287px;
  scroll-snap-align: start;
}
.team-card img {
  width: 100%; aspect-ratio: 2702 / 3384; object-fit: cover;
  border-radius: 16px;
  margin-bottom: 16px;
}
.team-card h3 { font-size: 26px; margin-bottom: 2px; }
.team-card p { font-size: 13px; color: var(--ink); }

.carousel-nav { display: flex; gap: 10px; }
.carousel-btn {
  width: 48px; height: 48px; padding: 0;
  border: 0; background: transparent; cursor: pointer;
  opacity: .9; transition: opacity .2s, transform .2s;
}
.carousel-btn img { width: 48px; height: 48px; }
.carousel-btn:hover { opacity: 1; transform: scale(1.04); }

/* ---------- CTA ---------- */
.cta { padding: var(--section-pad) 0 0; }
.cta-card {
  border-radius: var(--radius);
  padding: 112px 30px;
  text-align: center;
}
.cta-content { max-width: 646px; margin: 0 auto; }
.cta-content p { margin-bottom: 28px; }
.cta-content .btn { margin-top: 10px; }

.btn {
  display: inline-block;
  background: var(--btn-bg); color: var(--btn-ink);
  font-family: var(--font-ui);
  font-size: 16.5px; letter-spacing: normal;
  padding: 15px 37px; border-radius: 10px;
  transition: transform .2s ease, opacity .2s ease;
}
.btn:hover { transform: translateY(-2px); opacity: .92; }

/* ---------- Footer ---------- */
.site-footer {
  margin-top: var(--section-pad);
  background: var(--bg);
  overflow: hidden;
}
.footer-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  gap: 40px;
  padding-top: 24px;
}
.footer-brand .logo img { width: 150px; height: 37px; }
.footer-brand p { font-size: 13px; color: var(--ink); margin-top: 16px; max-width: 280px; }

.footer-col { display: flex; flex-direction: column; gap: 10px; }
.footer-col h4 { font-size: 13px; font-weight: 500; margin-bottom: 6px; }
.footer-col a { font-size: 13px; color: var(--ink); opacity: .8; transition: opacity .2s, color .2s; }
.footer-col a:hover { opacity: 1; color: var(--accent); }

.footer-bottom {
  margin-top: 48px; padding-top: 20px; padding-bottom: 20px;
  border-top: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.socials { display: flex; gap: 20px; }
.socials img { width: 20px; height: 20px; }
.socials a { opacity: .85; transition: opacity .2s; }
.socials a:hover { opacity: 1; }
.footer-bottom p { font-size: 11px; color: var(--ink); margin: 0; }

.footer-wordmark { width: 100%; display: block; }
/* Sobald das Skript die Zeichnung als SVG eingesetzt hat, verschwindet das
   PNG. Ohne Skript bleibt es stehen — dann ist der Fuss eben ruhig. */
.footer-wordmark.is-replaced { display: none; }

/* ---------- Die Leitungen im Fuss ----------
   Zwei Lagen pro Bahn: die ruhende Linie und darüber dieselbe Bahn in Mint,
   von der eine Maske aus Strich und Lücke nur ein kurzes Stück zeigt. Das
   Stück wandert über die Bahn — so läuft Licht durch die Leitung, statt dass
   die ganze Linie blinkt. `pathLength` normiert alle Bahnen auf 100, damit
   ein Wert für alle vier passt, wie lang sie in Wirklichkeit auch sind.
   Wichtig: pathLength ist ein SVG-Attribut, keine CSS-Eigenschaft — im
   Stylesheet gesetzt bleibt es wirkungslos und die Bahn zerfällt in viele
   kurze Striche statt eines wandernden Lichts. */
.footer-art { position: relative; display: block; }
.footer-circuit { display: block; width: 100%; height: 90px; }
.fc-line {
  fill: none; stroke: rgba(255, 255, 255, .1); stroke-width: 1.2;
  stroke-linecap: round; stroke-linejoin: round;
}
/* Eine Neonröhre, kein Flackermuster: die Bahn glimmt durchgehend schwach in
   Mint, und darin läuft ein langer heller Streifen mit weichen Enden durch —
   wie der Anlauf einer Leuchtstoffröhre. Zwei Lagen machen das: die ruhige
   Röhre und der wandernde Streifen darüber. */
.fc-tube {
  fill: none; stroke: var(--accent); stroke-width: 1.3; opacity: .3;
  stroke-linecap: round; stroke-linejoin: round;
  filter: drop-shadow(0 0 2px rgba(137, 184, 174, .45));
}
/* Vorher eine Volltonfarbe mit hartem Rand — jetzt ein Verlauf (siehe
   #fc-glow in script.js), der zur Mitte hin hell wird und zu beiden Enden
   auf 0 ausläuft: kein Umschalten mehr zwischen hell und dunkel, sondern ein
   Auf- und Abschwellen. Länger und langsamer als vorher, damit das Schwellen
   auch zu sehen ist statt nur zu blitzen. */
.fc-pulse {
  fill: none; stroke: url(#fc-glow); stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 46 54; stroke-dashoffset: 100;
  filter: drop-shadow(0 0 6px rgba(168, 218, 207, .7));
  animation: fc-run 10s cubic-bezier(.45, 0, .55, 1) infinite;
}
.fc-pulse-2 { animation-duration: 12.5s; animation-delay: -4s; }
.fc-pulse-3 { animation-duration: 8.5s; animation-delay: -2s; }
.fc-pulse-4 { animation-duration: 15s; animation-delay: -7.5s; }
@keyframes fc-run { from { stroke-dashoffset: 100; } to { stroke-dashoffset: -100; } }
.fc-node { fill: none; stroke: rgba(255, 255, 255, .16); stroke-width: 1; }
.fc-dot {
  fill: var(--accent-light); opacity: .35;
  animation: fc-blink 3.4s ease-in-out infinite;
}
.fc-node:nth-of-type(2n) + .fc-dot { animation-delay: -1.7s; }
@keyframes fc-blink { 0%, 100% { opacity: .25; } 50% { opacity: .9; } }

@media (max-width: 700px) {
  .footer-circuit { height: 62px; }
}
@media (prefers-reduced-motion: reduce) {
  .fc-pulse, .fc-dot { animation: none; }
  .fc-pulse { opacity: .5; stroke-dasharray: none; }
}

/* ---------- Placeholder pages (not yet rebuilt) ---------- */
.placeholder {
  padding-top: calc(var(--header-h) + 86px);
  min-height: 55vh;
}
.placeholder p { max-width: 480px; margin-bottom: 24px; }

/* ---------- Scroll reveal ---------- */
.reveal {
  opacity: 0; transform: translateY(24px);
  transition: opacity .7s ease, transform .7s ease;
}
/* Die Karten in einem Raster kommen einzeln und leicht kleiner herein —
   das Raster selbst trägt .reveal, die Karten staffeln sich darunter. */
.case-grid .case-card,
.package-grid .package-card,
.tier .svc {
  opacity: 0; transform: translateY(20px) scale(.955);
  transition: opacity .75s cubic-bezier(.16,1,.3,1), transform .75s cubic-bezier(.16,1,.3,1);
}
.case-grid.is-visible .case-card,
.package-grid.is-visible .package-card,
.tier .svc.is-visible {
  opacity: 1; transform: none;
}
.case-grid.is-visible .case-card:nth-child(2), .package-grid.is-visible .package-card:nth-child(2) { transition-delay: .09s; }
.case-grid.is-visible .case-card:nth-child(3), .package-grid.is-visible .package-card:nth-child(3) { transition-delay: .18s; }
.case-grid.is-visible .case-card:nth-child(4) { transition-delay: .27s; }
.tier-2 .svc:nth-child(2), .tier-3 .svc:nth-child(2) { transition-delay: .09s; }
.tier-2 .svc:nth-child(3), .tier-3 .svc:nth-child(3) { transition-delay: .18s; }

/* 3) Tiefe: die Medien wandern beim Scrollen minimal gegen die Karte.
   Verschoben wird der Bildausschnitt, nicht das Element — so bleibt der
   Rahmen stehen und nichts läuft über die Kante. */
.case-card img, .case-card video, .svc-media video {
  object-position: 50% calc(50% + var(--py, 0%));
}
.tier-1 .svc-media video { object-position: calc(28% ) calc(50% + var(--py, 0%)); }
.mix video:nth-child(2) { object-position: 26% calc(50% + var(--py, 0%)); }
.reveal.is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  .case-grid .case-card, .package-grid .package-card, .tier .svc { opacity: 1; transform: none; }
  .hero-media { transform: none; border-radius: 0; }
  .team-track { scroll-behavior: auto; }
}

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .story-grid { grid-template-columns: 1fr; }
  .vm-grid { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .team-head { flex-direction: column; align-items: flex-start; }
}

/* Die Pille sitzt absolut in der Mitte; mit der grösseren Schrift stösst sie
   auf mittleren Breiten ans Logo. Dort etwas enger setzen. */
@media (max-width: 1150px) and (min-width: 721px) {
  .main-nav a { font-size: 15.5px; padding: 8px 13px; }
}

@media (max-width: 720px) {
  .main-nav {
    position: fixed; inset: var(--header-h) 16px auto 16px;
    transform: none; left: auto;
    background: rgba(14, 15, 17, 0.96);
    border: 1px solid var(--line);
    box-shadow: none;
    flex-direction: column; gap: 0;
    padding: 8px;
    display: none;
  }
  .main-nav.open { display: flex; }
  .main-nav a { padding: 12px 16px; font-size: 15px; }
  .nav-toggle { display: block; }
  .footer-grid { grid-template-columns: 1fr; }
  .footer-bottom { flex-direction: column; align-items: flex-start; }
}

/* ---------- Focus visibility ---------- */
a:focus-visible, button:focus-visible, select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* =========================================================
   Components for the full site (home, services, cases, contact, terms)
   ========================================================= */

/* ---------- Button variants ---------- */
.btn-accent { background: var(--accent-light); color: #0e0f11; }
.btn-ghost {
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--ink);
}
/* Im Opener liegt der Ghost-Knopf auf bewegtem Film. Mit 2% Weiss war er dort
   praktisch durchsichtig: der Text schwamm auf dem Video, und je nach Bild war
   der Knopf gar nicht mehr als Fläche zu erkennen. Er bekommt darum echtes
   Milchglas — der Hintergrund wird hinter ihm unscharf und etwas heller, die
   obere Kante trägt einen feinen Lichtsaum, wie ihn eine Glasscheibe wirft.
   Nur im Opener; die Ghost-Knöpfe auf ruhigem Grund brauchen das nicht.
   Browser ohne backdrop-filter zeigen weiter die flache Fläche, dann aber mit
   den kräftigeren Werten von hier — der Knopf bleibt also in jedem Fall
   sichtbar. */
/* Nicht Milchglas, sondern eine Scheibe: milchig wird es, wenn nur unscharf
   gerechnet wird — dann liegt ein gleichmässiger Schleier über allem und nichts
   verrät, dass da Glas ist. Glas erkennt man an den Kanten, nicht an der
   Fläche. Genau darum ist hier wenig Weiss im Spiel und das meiste davon sitzt
   auf einem Pixel Oberkante:

   1. der Grund dahinter wird unscharf und etwas farbiger — Glas sammelt Licht,
      statt es zu schlucken;
   2. ein flacher Verlauf über der Fläche als Wölbung, kaum sichtbar;
   3. eine helle Oberkante und ein schwacher Rückschein unten. Das ist der
      Teil, der die Scheibe verrät.

   Ein wanderndes Streiflicht beim Darüberfahren war einmal da und ist wieder
   weg: es zog den Blick auf sich und wirkte aufgesetzt. Ein Knopf im Opener
   darf sich melden, wenn der Cursor kommt, aber nicht glitzern. */
.hero-cta .btn-ghost {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: linear-gradient(148deg,
              rgba(255, 255, 255, 0.11) 0%,
              rgba(255, 255, 255, 0.035) 40%,
              rgba(255, 255, 255, 0.02) 64%,
              rgba(255, 255, 255, 0.07) 100%);
  border-color: rgba(255, 255, 255, 0.20);
  -webkit-backdrop-filter: blur(20px) saturate(165%) brightness(1.03);
          backdrop-filter: blur(20px) saturate(165%) brightness(1.03);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.30),
              inset 0 -1px 0 rgba(255, 255, 255, 0.08),
              0 10px 28px rgba(0, 0, 0, 0.26);
  transition: transform .2s ease, opacity .2s ease,
              box-shadow .35s ease, background .35s ease, border-color .35s ease;
}
/* Das Glanzlicht der Wölbung — sehr zurückgenommen, es soll die Kante oben
   nur andeuten. Liegt über dem Grund, aber unter der Schrift; dafür sorgt das
   isolation/z-index-Paar. */
.hero-cta .btn-ghost::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(135% 100% at 22% -25%,
              rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0) 60%);
}
.hero-cta .btn-ghost:hover {
  background: linear-gradient(148deg,
              rgba(255, 255, 255, 0.16) 0%,
              rgba(255, 255, 255, 0.06) 40%,
              rgba(255, 255, 255, 0.04) 64%,
              rgba(255, 255, 255, 0.11) 100%);
  border-color: rgba(255, 255, 255, 0.30);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.42),
              inset 0 -1px 0 rgba(255, 255, 255, 0.11),
              0 14px 34px rgba(0, 0, 0, 0.30);
}

/* ---------- Hero (video background) ---------- */
.hero {
  position: relative;
  background: var(--bg);
  min-height: clamp(560px, 92vh, 860px);
  /* Siehe .hero:has(+ .ticker) weiter unten: auf der Startseite endet der
     Opener früher, damit das Markenband nicht unter die Fensterkante rutscht. */
  display: flex; align-items: center;
  padding-top: var(--header-h);
  overflow: hidden;
}
/* iOS blendet über ein Video, das nicht von selbst startet, einen grossen
   Play-Knopf ein — im Opener sah das aus wie ein Fehler im Bild. Diese
   Steuerelemente gehören zu Videos mit `controls`; unsere laufen stumm im
   Hintergrund und brauchen sie nicht. */
video::-webkit-media-controls-start-playback-button,
video::-webkit-media-controls-play-button,
video::-webkit-media-controls-panel {
  display: none !important;
  -webkit-appearance: none;
}
.hero-media, .hero-media video, .hero-media img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
/* Der Film sitzt etwas tiefer im Rahmen als in der Mitte — es war oben zu viel
   Luft. Weil `cover` den Rahmen immer voll ausfüllt, kann dabei nie eine Kante
   auftauchen, egal welcher Wert hier steht: verschoben wird nur, welcher
   Ausschnitt weggeschnitten wird. Kleinerer Y-Wert = Bild rutscht nach unten. */
.hero-media video, .hero-media img { object-position: 50% 10%; }
/* Der dunkle Verlauf, der den Opener unten ins Seitenschwarz auflöst — genau
   dort, wo das Markenband beginnt. Die Haltepunkte liegen jetzt etwas tiefer
   im Bild, damit vom Film noch ein Stück mehr zu sehen ist, bevor er
   verschwindet. */
.hero-media::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(rgba(10, 11, 12, 0.22), rgba(14, 15, 17, 0.34) 65%, rgba(14, 15, 17, .82) 90%, var(--bg));
}
/* Beim Scrollen zieht sich der Opener zurück: das Bild verkleinert sich und
   seine Ränder laufen ins Seitenschwarz, statt an einer sichtbaren Kante zu
   enden — ein verkleinerter heller Kasten auf dunklem Grund sah billig aus.
   Die Werte setzt das Skript als --hero-scale / --hero-edge. */
/* Nicht der Rahmen schrumpft, sondern das Video darin.
   Vorher trug die geclippte Box selbst die Skalierung: ihre Kante bewegte
   sich mit, wurde bei jedem Frame neu gerastert und blendete gegen nichts —
   daher der helle Saum, der nur beim Scrollen auftrat. Jetzt steht die Box
   still und deckt die volle Breite, in Seitenfarbe hinterlegt; einzig das
   Video darin wird kleiner. Was aussen frei wird, ist gemalter Hintergrund,
   keine offene Kante. */
.hero-media {
  overflow: hidden;
  background: var(--bg);
  border-radius: 0;
}
.hero-media video, .hero-media img {
  transform: scale(var(--hero-scale, 1));
  transform-origin: 50% 0;
  backface-visibility: hidden;
  will-change: transform;
}
/* Der Saum: vier Verläufe, die mit dem Scrollen aufziehen und alle vier
   Kanten in die Seitenfarbe legen. Bei --hero-edge: 1 ist der Rand des
   Films nicht mehr zu sehen, er löst sich einfach in die Seite auf. */
.hero-media::before {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  /* Der Saum liegt von Anfang an über dem Bild, nicht erst beim Scrollen —
     sonst blitzt beim ersten Radklick die helle Bildkante auf. */
  opacity: var(--hero-edge, .85);
  background:
    linear-gradient(90deg,  var(--bg) 0%, rgba(14, 15, 17, 0) 11%),
    linear-gradient(270deg, var(--bg) 0%, rgba(14, 15, 17, 0) 11%),
    linear-gradient(0deg,   var(--bg) 0%, rgba(14, 15, 17, 0) 14%),
    linear-gradient(180deg, var(--bg) 0%, rgba(14, 15, 17, 0) 10%);
}
.hero-content { will-change: transform, opacity; }
.hero-content { position: relative; z-index: 1; width: 100%; }
/* Auf dem Telefon steht der Opener still (siehe script.js). Ohne Bewegung
   braucht auch nichts eine eigene Ebene auf der Grafikkarte — die kostet dort
   Speicher und bringt nichts. */
@media (max-width: 700px), (pointer: coarse) {
  .hero-content { will-change: auto; }
  .hero-media video, .hero-media img { will-change: auto; }
}
.hero h1 {
  /* Unter 420px passte das längste Wort nicht mehr in die Zeile und wurde an
     der Bildschirmkante abgeschnitten — NIKEA bricht Wörter nicht um. Der
     untere Wert des Bereichs richtet sich deshalb nach der Fensterbreite. */
  font-size: clamp(26px, min(calc(24px + 2.5vw), calc(8vw - 4px)), 84px);
  line-height: 1.1;
  letter-spacing: -1.07px;
  margin-bottom: 18px;
  max-width: 15ch;
}
/* The German headline is 76 characters against the English 47, and NIKEA is a
   caps-only face, so the same size stacks it six lines deep and pushes the
   buttons off the fold. Slightly smaller type over a wider measure brings it
   back to three lines without touching the English page. */
html[lang="de"] .hero h1 {
  font-size: clamp(32px, calc(16px + 2vw), 58px);
  max-width: 26ch;
}
.hero-center { text-align: center; }
.hero-center h1 { margin-inline: auto; }
.hero .hl { color: var(--accent-light); }
/* Outfit rather than the body face, and grey rather than white: the original
   sets this line back from the headline instead of competing with it. */
.hero-sub {
  max-width: 600px;
  font-family: var(--font-title);
  font-size: 18px; line-height: 1.55;
  color: var(--ink-soft);
  margin-bottom: 32px;
}
.hero-center .hero-sub { margin-inline: auto; }
.hero-cta { display: flex; gap: 14px; flex-wrap: wrap; }
.hero-center .hero-cta { justify-content: center; }

/* chips above the services hero title */
.chip-row { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; margin-bottom: 28px; }
.chip {
  display: flex; align-items: center; gap: 8px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(0, 0, 0, 0.35);
  border-radius: 999px; padding: 10px 16px;
  font-size: 13px; color: var(--ink);
}
.chip img { width: 20px; height: 20px; }

/* ---------- Brand logo ticker ----------
   On the live site each logo sits in its own translucent rounded tile:
   tile 204x56 (164x40 image + 8px/20px padding), #73737329, radius 12px,
   10px apart. content-box keeps the padding outside the 164x40 image box. */
/* Die Kacheln liefen bisher hart in die Bildschirmkante. Auf dem Telefon ist
   das die halbe Ansicht — eine angeschnittene Kachel sieht dort nach Fehler
   aus. Eine Maske lässt die Reihe an beiden Enden ausblenden, statt sie
   abzuschneiden. */
.ticker {
  overflow: hidden; padding: 28px 0 40px;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
}
/* Nur die Startseite trägt das Markenband. Ihr Opener endet deshalb früher als
   der auf den Unterseiten: in einem Browserfenster ohne Vollbild — und so
   sitzen die meisten davor — begann das Band sonst genau an der Fensterkante
   und war schlicht nicht zu sehen. Jetzt ragt es rund hundert Pixel herein. */
.hero:has(+ .ticker) { min-height: clamp(520px, 78vh, 760px); }
/* Auf dem Telefon soll beim Laden nur die erste Reihe der Marken ganz zu
   sehen sein — die zweite darf gerade so anschneiden, damit klar ist, dass
   sich dort etwas bewegt und es weitergeht. Der Opener nimmt darum mehr vom
   ersten Bildschirm ein als vorher. */
@media (max-width: 700px) { .hero:has(+ .ticker) { min-height: clamp(480px, 89vh, 716px); } }
/* will-change und translate3d schieben das Band auf die Grafikkarte. Ohne das
   rechnet der Browser bei jedem Bild neu und die Kacheln flimmern an den
   Kanten — das war der Rendering-Fehler. */
.ticker-row {
  display: flex; align-items: center; gap: 10px; width: max-content;
  animation: ticker 70s linear infinite;
  will-change: transform; backface-visibility: hidden;
}
/* Partner logos arrive as dark artwork on transparency, each sitting in a
   differently proportioned canvas — content filled anywhere from 20% to 74%
   of the file's height. The PNGs are now trimmed to their artwork, so
   `contain` gives every logo the same height instead of the same crop, and
   the filter flattens twelve different inks to one light grey. Together
   that is what makes the strip read as one row rather than a jumble. */
.ticker-row img {
  /* Die Kachel misst 172x62 und bleibt dabei. Was sich ändert, ist der Kasten
     für das Logo darin — das Polster trägt die Differenz.

     `contain` legt jedes Logo in diesen Kasten, und je nach Zeichnung klemmt
     es an der Breite oder an der Höhe. Gemessen: die kompakten Marken klemmen
     alle an der Höhe (Andermatt quadratisch, füllte nur 30% der Fläche; AR
     52%, Fisherman's 57%), die langen Wortmarken an der Breite. Darum wächst
     die Höhe deutlich (42→48, +14%) und die Breite kaum (140→146, +4%): das
     hebt genau die kleinen an, ohne die breiten an den Rand zu drücken.

     Das seitliche Polster steckt in --tile-pad-x, damit die Kachelbreite an
     einer Stelle zu ändern ist. */
  /* Die Kachel ist der feste Rahmen, das Logo die Variable darin: das Polster
     wird aus der Differenz gerechnet, damit jede Kachel gleich gross bleibt,
     egal wie gross das Logo darin steht. Vorher stand das Polster als Zahl da
     und musste bei jeder Grössenänderung von Hand nachgerechnet werden.

     Gemessen: alle zehn PNG-Logos liegen als 328x80 vor und klemmen deshalb
     ausnahmslos an der *Breite* — die 48px Höhe werden nie ausgereizt, das
     Logo wird 146x36 gezeichnet. Für sie zählt also allein --logo-w. Apple
     (150x150) und Flims (300x122) klemmen umgekehrt an der Höhe; dort wirkt
     nur --logo-h. Wer eines der Logos vergrössern will, dreht an der Achse,
     an der es klemmt — die andere tut nichts. */
  --tile-w: 172px;
  --tile-h: 62px;
  --logo-w: 157.388px;   /* 146 +10%, dann -2% */
  --logo-h: 48px;
  width: var(--logo-w); height: var(--logo-h);
  object-fit: contain;
  box-sizing: content-box;
  padding: calc((var(--tile-h) - var(--logo-h)) / 2)
           calc((var(--tile-w) - var(--logo-w)) / 2);
  background: rgba(115, 115, 115, 0.16);
  border-radius: 12px;
  filter: brightness(0) invert(1) opacity(0.65);
}
/* Drei Marken tanzen aus der Reihe. LAAX ist die Wortmarke des Skigebiets:
   vier breite Versalien, die bei voller Grösse neben den anderen auftrumpfen —
   sie liegt darum eine Stufe tiefer. Apple und Flims Laax Falera füllen die
   Kachel schon in der Höhe aus, und bei ihnen greift auch nur die Höhe: die
   Breite tut dort nichts. Flims Laax Falera steht zudem als einzige zweizeilig
   und wirkt bei gleicher Höhe grösser als die einzeiligen Wortmarken daneben,
   darum noch einmal 5% weniger.

   Andermatt Sedrun Disentis geht in die andere Richtung: die Zeichnung ist ein
   kleiner Kasten mit viel Luft ringsum in der Datei, steht also selbst bei
   voller Kastenbreite kleiner da als die Wortmarken. Sie bekommt 5% mehr statt
   2% weniger. Das Polster der Kachel schrumpft dadurch auf 1.7px (Desktop) —
   das fällt nicht auf, weil die Zeichnung mittig sitzt und die Tinte die Kante
   nie erreicht. */
.ticker-row img[src$="apple.svg"] { --logo-h: 38.32px; --logo-w: 146px; }
.ticker-row img[src$="flims.svg"] { --logo-h: 33.355px; --logo-w: 146px; }
.ticker-row img[src$="brand-07.png"] { --logo-w: 168.63px; }
.ticker-row img[src$="brand-08.png"] { --logo-w: 150.234px; }
/* Formaziun Surselva ist die jüngste Marke und stand neben den Wortmarken zu
   zurückhaltend da. Sie liegt als einzige dreifach aufgelöst vor (984x240),
   die Breite hier ist also nur der Kasten — an der Schärfe ändert sie nichts. */
.ticker-row img[src$="surselva.png"] { --logo-w: 165.257px; }
@keyframes ticker { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(-50%, 0, 0); } }

/* Die zweite Reihe gibt es nur auf dem Telefon. Dort ist das Band so schmal,
   dass in einer einzigen Reihe kaum eine Marke vorbeikommt, während man
   scrollt — zwei gegenläufige Reihen zeigen in derselben Zeit das Vierfache.
   Sie läuft rückwärts durch dieselben Keyframes, nicht durch eigene. */
.ticker-row-back { display: none; }
@media (max-width: 700px) {
  .ticker {
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 12%, #000 88%, transparent 100%);
            mask-image: linear-gradient(90deg, transparent 0, #000 12%, #000 88%, transparent 100%);
    /* Auf dem Telefon steht das Band knapp unter der Fensterkante — die
       zweite Reihe wurde dort halb abgeschnitten. Weniger Luft nach oben
       holt beide Reihen ins Bild, ohne den Opener zu stauchen. */
    padding-top: 12px;
  }
  .ticker-row { animation-duration: 46.2s; }
  .ticker-row-back {
    display: flex; margin-top: 10px;
    animation-direction: reverse;
  }
  /* Schmalere Kachel, gleich grosses Logo: auf dem Telefon bleibt vom Polster
     nur der Rest zwischen Logo und Kachelkante. Die Kachel misst hier 169.4px
     statt 172 — enger geht nicht, ohne dass die Wortmarken die Kante berühren. */
  .ticker-row img { --tile-w: 169.4px; }
  /* Oben und unten laufen zwei verschiedene Hälften der Kundenliste: die
     Reihen laufen gegeneinander, und stünde dieselbe Marke in beiden, würde
     sie sich irgendwann selbst kreuzen. Reihe eins zeigt auf dem Telefon nur
     die erste Hälfte, Reihe zwei nur die zweite. Auf dem Desktop gibt es die
     zweite Reihe nicht — dort trägt Reihe eins wieder alle Marken. */
  .ticker-row img.ticker-wide-only { display: none; }
}

/* ---------- Testimonial marquee ---------- */
.testi-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 24px; margin-bottom: 40px;
}
.testi-head .h2 { margin-bottom: 0; }
/* Three cards, then it steps. The viewport is held to the page's own 1220px
   instead of running full-bleed, so exactly three fit and the fourth is the
   thing the carousel scrolls to. */
.testi-viewport {
  overflow: hidden;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 30px;
}
/* A stepping carousel, not a marquee: quotes need to hold still long enough
   to be read, and the arrows need something discrete to step through. */
.testi-track {
  display: flex; gap: 24px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding-bottom: 8px;
  scrollbar-width: none;
}
.testi-track::-webkit-scrollbar { display: none; }
.testi-card {
  position: relative; overflow: hidden;
  flex: 0 0 calc((100% - 48px) / 3); scroll-snap-align: start;
  height: 560px;
  border-radius: 16px;
  display: flex; flex-direction: column; justify-content: space-between;
}
.testi-card > .bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.testi-card::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(rgba(8, 9, 10, 0.25), rgba(8, 9, 10, 0.72));
}
.testi-quote, .testi-person { position: relative; z-index: 1; padding: 26px; }
.testi-quote { font-family: var(--font-title); font-size: 23px; line-height: 1.35; color: var(--ink); }
.testi-person { display: flex; align-items: center; gap: 12px; }
.testi-person img { width: 48px; height: 48px; border-radius: 50%; object-fit: cover; }
.testi-person strong { display: block; font-family: var(--font-title); font-weight: 600; font-size: 16px; color: var(--ink); }
.testi-person span { font-size: 11px; color: rgba(255, 255, 255, 0.75); }

/* ---------- Growth package teaser cards (home) ---------- */
.package-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.package-card {
  position: relative; overflow: hidden;
  border-radius: 16px; aspect-ratio: 368 / 465;
  display: flex; flex-direction: column; justify-content: space-between;
  padding: 28px;
}
.package-card > .bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Die Teaser sind Bildkarten mit Text darauf, und Text auf bewegtem Bild geht
   unter, sobald das Bild hell wird. Zwei Mittel dagegen: das Material bekommt
   eine ruhige Abstufung — etwas weniger Farbe, etwas mehr Kontrast, deutlich
   dunkler —, und darüber liegt ein Verlauf, der unten fast deckt. Zusammen
   ergibt das den Eindruck, den ein Filmplakat hat: Bild als Grund, Schrift als
   Vordergrund, nichts kämpft. */
.package-card .mosaic { filter: saturate(.9) contrast(1.05) brightness(.92); }
.package-card::after {
  content: ""; position: absolute; inset: 0;
  /* Nicht die ganze Karte abdunkeln, sondern den Streifen, auf dem die Schrift
     liegt — und die sitzt hier oben, nicht unten. Also deckt der Verlauf oben
     stark und lässt die untere Hälfte offen, wo nur Bild ist. Ein leichter
     Fuss unten hält die Karte trotzdem am Boden. */
  background:
    linear-gradient(180deg,
      rgba(8, 9, 10, .88) 0%,
      rgba(8, 9, 10, .7) 20%,
      rgba(8, 9, 10, .34) 44%,
      rgba(8, 9, 10, .26) 68%,
      rgba(8, 9, 10, .5) 100%),
    radial-gradient(140% 90% at 50% 78%, rgba(8, 9, 10, 0) 40%, rgba(8, 9, 10, .3) 100%);
}
.package-card .icon, .package-card .pack-text { position: relative; z-index: 2; }
/* Der Lichtschein folgt dem Cursor. Er sitzt auf den Teasern, nicht auf der
   Leistungsseite: diese drei Karten sind Links, der Schein zeigt also auf
   etwas, das man anklicken kann. Die Position setzt das Skript. */
.package-card::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  opacity: 0; transition: opacity .4s ease;
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%), rgba(137, 184, 174, 0.22), transparent 62%);
}
.package-card:hover::before { opacity: 1; }
.package-card .icon { width: 38px; height: 42px; }
.package-card h3 { font-size: 28px; margin-bottom: 8px; text-shadow: 0 2px 18px rgba(0, 0, 0, .6); }
.package-card p { font-size: 13px; color: rgba(255, 255, 255, 0.86); text-shadow: 0 1px 12px rgba(0, 0, 0, .7); }

/* ---------- Package detail cards (services) ---------- */
.package-detail {
  position: relative; overflow: hidden;
  border-radius: var(--radius);
  padding: clamp(28px, 4vw, 44px);
}
.package-detail > .bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.package-detail::after { content: ""; position: absolute; inset: 0; background: rgba(10, 11, 12, 0.82); }
.package-detail > div { position: relative; z-index: 1; }
.package-detail h3 {
  font-family: var(--font-display); font-weight: 400; text-transform: uppercase;
  font-size: clamp(26px, 2.6vw, 34px); line-height: 1.2; margin-bottom: 20px;
}
.package-detail p { font-size: 14px; }
.package-detail .package-cta { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 28px; }
.package-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-bottom: 24px; }
.price-pill {
  display: inline-block; font-size: 13px; padding: 11px 32px;
  border-radius: 10px; border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--ink); background: rgba(255, 255, 255, 0.04);
}

/* ---------- Case study cards ---------- */
/* Drei Cases pro Reihe: schmalere Karten, mehr Arbeiten im Blick, ohne dass
   man scrollen muss. Darunter zwei, auf dem Telefon eine. */
.case-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.case-card {
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(255, 255, 255, 0.02);
  border-radius: 16px; padding: 20px;
}
.case-card img, .case-card video {
  width: 100%; aspect-ratio: 5 / 3; object-fit: cover;
  border-radius: 10px; margin-bottom: 20px;
  display: block; background: rgba(255, 255, 255, 0.04);
}
.case-card h3 {
  font-family: var(--font-display); font-weight: 400; text-transform: uppercase;
  font-size: 22px; letter-spacing: 0.02em; margin-bottom: 4px;
}
.case-card p { font-size: 15px; margin-bottom: 16px; }
.center-btn { text-align: center; margin-top: 36px; }

/* ---------- FAQ accordion ---------- */
.faq-grid { display: grid; grid-template-columns: 1fr 1.2fr; gap: clamp(32px, 5vw, 72px); align-items: start; }
.faq-intro p { margin-bottom: 24px; }
.faq-item { border-bottom: 1px solid var(--line); }
.faq-item summary {
  display: flex; justify-content: space-between; align-items: center; gap: 16px;
  padding: 20px 0; cursor: pointer; list-style: none;
  font-size: 15px; color: var(--ink);
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "+"; flex: 0 0 28px; height: 28px;
  display: grid; place-items: center;
  background: var(--accent); color: #0e0f11;
  border-radius: 6px; font-size: 16px;
}
.faq-item[open] summary::after { content: "\2212"; }
.faq-item p { padding-bottom: 20px; max-width: 60ch; }

/* ---------- Stats ---------- */
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(24px, 3vw, 40px); }
/* ---------- Das gezeichnete Smiley ----------
   Aus dem getippten :) in der Überschrift ist eine Zeichnung geworden, die
   sich selbst zieht, sobald der Abschnitt erscheint: erst der Kreis — der am
   Ende ein Stück über den Anfang hinausläuft, wie ein Stift, der noch einmal
   nachfasst —, dann die zwei Augen, dann der Mund. Zusammen knapp drei
   Sekunden. `pathLength="1"` im SVG macht jede Linie gleich lang, egal wie
   lang sie wirklich ist; darum genügt hier ein einziger Strichwert. */
.smiley {
  width: .92em; height: .92em; vertical-align: -.1em;
  margin-left: .12em; overflow: visible;
}
.smiley path {
  fill: none; stroke: var(--accent);
  stroke-width: 4; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 1; stroke-dashoffset: 1;
}
@keyframes smiley-draw { to { stroke-dashoffset: 0; } }
.section-head.is-visible .smiley-face  { animation: smiley-draw 1.5s cubic-bezier(.45,.05,.3,1) .15s forwards; }
.section-head.is-visible .smiley-eye-l { animation: smiley-draw .2s ease-out 1.75s forwards; }
.section-head.is-visible .smiley-eye-r { animation: smiley-draw .2s ease-out 1.98s forwards; }
.section-head.is-visible .smiley-mouth { animation: smiley-draw .9s ease-out 2.2s forwards; }
@media (prefers-reduced-motion: reduce) {
  .smiley path { stroke-dashoffset: 0; animation: none !important; }
}

.stat-num { font-family: var(--font-title); font-size: 56px; color: var(--ink); line-height: 1.1; }
.stat-num sup { font-size: 28px; }
.stat h4 { font-size: 16px; margin: 6px 0; }
.stat p { font-size: 13px; }

/* ---------- CTA background image ---------- */
/* ---------- Der Zug im Schlussblock ----------
   Es fährt das Bild selbst, nicht ein nachgebautes Raster: dieselbe körnige
   grüne Fläche wie vorher, nur zweimal nebeneinander — die zweite Kopie
   gespiegelt, damit an der Naht Hell auf Hell trifft und man den Übergang
   nicht sieht. Die Bahn ist doppelt so breit wie die Karte und wandert um
   ihre halbe Breite; danach beginnt sie von vorn, ohne Sprung.

   Gefahren wird in Stufen, nicht gleitend: 90 Sprünge in 9 Sekunden, also
   zehn pro Sekunde. Das ist das Ruckeln eines Films, kein Schweben — und es
   ist das, was man als Trrr-Tack-Tack liest.

   Darüber liegt eine feine Rauschschicht, die das Korn des Bildes verstärkt,
   und ein dunkler Schleier, damit die Schrift steht. Das Grün ist über einen
   Filter Richtung Salbei gezogen und abgedunkelt. */
.cta-card { position: relative; overflow: hidden; background: #0c1210; }
.cta-rail {
  position: absolute; inset: 0; z-index: 0; display: flex; width: 200%;
  animation: cta-run 9s steps(90, end) infinite;
}
.cta-bg {
  flex: 0 0 50%; width: 50%; height: 100%; object-fit: cover;
  /* Weniger Sättigung, ein Hauch Richtung Salbei, dunkler. */
  filter: saturate(.78) hue-rotate(-6deg) brightness(.68) contrast(1.08);
  /* Drei Prozent Überstand: die Vorlage hat einen dunklen Rand eingebrannt,
     der an der Naht sonst als feine Linie durchs Bild wandert. */
  transform: scaleX(1.03);
}
.cta-bg-flip { transform: scaleX(-1.03); }
@keyframes cta-run { to { transform: translateX(-50%); } }

/* Das Korn: ein feines Rauschen, das über allem liegt und mitfährt — erzeugt
   im Browser, keine zusätzliche Datei. Ohne diese Schicht wirkt das bewegte
   Bild glatter als das stehende, weil Bewegung Korn optisch verschluckt. */
.cta-card::before, .vm-media::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  background-size: 180px 180px;
  opacity: .22; mix-blend-mode: overlay;
  animation: cta-grain .5s steps(3, end) infinite;
}
/* Das Korn springt drei Mal pro halber Sekunde umher — stehendes Rauschen
   sieht aus wie Schmutz auf dem Bildschirm, wanderndes wie Film. */
@keyframes cta-grain {
  0%   { background-position: 0 0; }
  33%  { background-position: -60px 30px; }
  66%  { background-position: 40px -50px; }
  100% { background-position: -20px 20px; }
}
.cta-card::after, .vm-media::after {
  content: ""; position: absolute; inset: 0; z-index: 2;
  background: linear-gradient(100deg, rgba(8, 10, 9, .52) 0%, rgba(8, 10, 9, .46) 55%, rgba(8, 10, 9, .54) 100%);
}
/* Das Porträt steht vor allen Schichten des fahrenden Grundes. */
.vm-media .vm-portrait { position: relative; z-index: 3; }
.cta-content { position: relative; z-index: 3; }
/* Der Knopf rüttelt alle paar Sekunden kurz — als wolle er losfahren. Dazwischen
   steht er still; ein dauerndes Zittern wäre nach zehn Sekunden unerträglich. */
/* Der Knopf ruckelt gleich, wenn man ankommt, und dann alle zweieinhalb
   Sekunden wieder — als stünde er unter Strom. */
.cta-content .btn { animation: cta-shake 2.6s cubic-bezier(.36,.07,.19,.97) .25s infinite; }
.cta-content .btn:hover { animation-duration: 1.3s; }
@keyframes cta-shake {
  0%        { transform: translate3d(0, 0, 0) rotate(0deg); }
  3%        { transform: translate3d(-2.5px, 0, 0) rotate(-.7deg); }
  6%        { transform: translate3d(2.5px, 0, 0) rotate(.7deg); }
  9%        { transform: translate3d(-3px, 1px, 0) rotate(-.6deg); }
  12%       { transform: translate3d(3px, -1px, 0) rotate(.6deg); }
  15%       { transform: translate3d(-2px, 0, 0) rotate(-.35deg); }
  18%       { transform: translate3d(1.5px, 0, 0) rotate(.25deg); }
  21%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
}
@media (prefers-reduced-motion: reduce) {
  .cta-rail, .cta-card::before, .vm-media::before, .cta-content .btn { animation: none; }
}
.cta-content p { color: rgba(255, 255, 255, 0.85); }

/* ---------- Forms ---------- */
/* Fields carry no border on the live site — the panel is a subtle vertical
   gradient with a 12px radius and 20px of padding, giving 67px-tall text
   fields and a 179px textarea. */
.contact-form { display: flex; flex-direction: column; gap: 12px; max-width: 100%; }
.contact-form input, .contact-form textarea {
  width: 100%; font: inherit; font-size: 16px; color: var(--ink);
  background: linear-gradient(rgb(15, 17, 18) 0%, rgba(103, 103, 103, 0.2) 100%);
  border: 0; border-radius: 12px; padding: 20px;
  line-height: 27px;
}
.contact-form input { height: 67px; }
.contact-form ::placeholder { color: rgba(255, 255, 255, 0.5); }
.contact-form textarea { min-height: 179px; resize: vertical; }
.contact-form .btn {
  align-self: flex-start; border: 0; cursor: pointer;
  font-size: 15px; line-height: 22px; padding: 14px 28px; margin-top: 21px;
}
.contact-form .btn:disabled { cursor: default; opacity: .65; transform: none; }

/* Honeypot: off-screen rather than display:none, because some bots skip
   hidden fields. Real visitors never reach it — it is out of the tab order
   and hidden from screen readers. */
.hp-field {
  position: absolute !important;
  left: -9999px; width: 1px; height: 1px;
  opacity: 0; pointer-events: none;
}

.form-status { font-size: 14px; margin: 0; }
.form-status:empty { display: none; }
.form-status.is-error { color: #ff9b8a; }

/* Replaces the form once the message is away. */
.form-done {
  border: 1px solid var(--accent);
  background: rgba(137, 184, 174, 0.08);
  border-radius: 12px; padding: 28px 24px;
}
.form-done h3 {
  font-family: var(--font-display); font-weight: 400; text-transform: uppercase;
  font-size: 24px; letter-spacing: normal; color: var(--accent-light);
  margin: 0 0 8px;
}
.form-done p { margin: 0; }
.form-done-links { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 20px; }
.form-done-links .btn { padding: 10px 20px; font-size: 14px; }

/* ---------- Contact page ----------
   Measured from the live site at 1280px: a centred 59px title, then two
   columns — map (590x274) with the address details beneath it on the
   left, form (537 wide) on the right, 77px apart. */
.page-title {
  font-size: clamp(40px, calc(27px + 2.5vw), 88px);
  line-height: 1.1;
  text-align: center; margin-bottom: 44px;
}
.contact-layout {
  display: grid;
  grid-template-columns: 622fr 537fr;
  gap: 61px;
  align-items: start;
  margin-bottom: 48px;
}
/* The map and details sit in a bordered card, 622px wide with 16px of
   padding — which is what puts the 590px map at x=46. On the live site the
   border is drawn by an ::after pseudo-element rather than on the box. */
.contact-info {
  /* outline rather than border: it draws in the same place but takes no
     layout space, so the map stays a full 590px like the live site's
     pseudo-element border. */
  outline: 1px solid rgba(255, 255, 255, 0.1);
  outline-offset: -1px;
  border-radius: 16px;
  padding: 16px;
}
.map-img {
  width: 100%; aspect-ratio: 590 / 274; object-fit: cover;
  border-radius: 8px; display: block;
}
.map-img { margin-bottom: 10px; }

/* ---------- Kontaktkarte ----------
   Vorher lag hier ein Stock-Bild irgendeiner Stadt. Jetzt ist es Laax:
   Strassen, Haeuser, See und Bach als Vektor, damit sich die Karte zeichnen
   kann statt nur dazuliegen. Der Aufbau geht vom Buero nach aussen und ist
   nach 3 s fertig; davor liegt nur die leere Flaeche da. Ausgeloest wird er
   von `.is-visible` am umgebenden `.reveal` — kein eigenes Skript noetig.
   Die Verzoegerung jedes Teils steckt als `--d` im Markup, die Dauer der
   gezeichneten Linien als `--t`; `pathLength="1"` macht jede Linie gleich
   lang, sodass eine Strichlaenge von 1 immer die ganze Strecke abdeckt. */
.map-frame {
  position: relative; width: 100%; aspect-ratio: 590 / 274;
  border-radius: 8px; overflow: hidden; margin-bottom: 10px;
  background: #f1f2ef;
}
.map-draw { display: block; width: 100%; height: 100%; }

.mp-ground { fill: #f1f2ef; }
/* Die Schummerung liegt als kleines PNG unter allem und gibt dem Hang die
   Form, die eine Hoehenlinie nur andeutet. Sie wird in `build-map.py` aus
   demselben Hoehenraster gerechnet, Licht von Nordwesten. */
.mp-relief { mix-blend-mode: multiply; }
/* Bodenbedeckung in den Markenfarben: jeder Ton ist das Salbeigruen des
   Logos, verschieden weit in den Kartengrund gemischt. Wald traegt am
   meisten, Wiese am wenigsten. */
.mp-wood   { fill: #bfd6d0; }
.mp-scrub  { fill: #d4e2dd; }
.mp-park   { fill: #d9e5e0; }
.mp-sport  { fill: #dfe8e4; }
.mp-grass  { fill: #e4eae6; }
.mp-farm   { fill: #e8ede9; }
.mp-yard   { fill: #e7e8e5; }
.mp-rock   { fill: url(#mpRock); }
.mp-wet    { fill: #d6e3e3; }
.mp-pool,
.mp-water  { fill: #c9dce4; stroke: #8db4c4; stroke-width: .7; vector-effect: non-scaling-stroke; }

/* Alle Striche und der Saum der Schrift liegen in Bildschirmpunkten, nicht in
   viewBox-Einheiten (`vector-effect`). Sonst waere die Karte auf dem Telefon
   ein grauer Schleier: der viewBox ist 1180 breit, die Spalte auf dem Telefon
   rund 300 — jeder Strich schrumpfte auf ein Viertel. */
.mp-stream, .mp-ct, .mp-cti, .mp-cth,
.mp-r1, .mp-r2, .mp-r3, .mp-r4,
.mp-r1c, .mp-r2c { fill: none; vector-effect: non-scaling-stroke; }
.mp-stream { stroke: #a5c4d1; stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round; }
/* Hoehenlinien wie auf der Landeskarte: warmes Graubraun, jede hundertste
   Stufe kraeftiger. Sie tragen die Hangform und muessen leise bleiben. */
.mp-cth { stroke: #d3c7b6; stroke-width: .4; }   /* Zwischenlinie */
.mp-ct  { stroke: #bfad93; stroke-width: .6; }   /* volle Linie, 20 m */
.mp-cti { stroke: #a08a6b; stroke-width: .95; }  /* Zaehllinie, 100 m */
/* Die Zahl steht in der Luecke der Zaehllinie, in deren Neigung. */
.mp-ctlbl {
  fill: #93795a; font-family: var(--font-ui); font-size: 19px; font-weight: 500;
  text-anchor: middle; dominant-baseline: middle; letter-spacing: .01em;
}
/* Massstabsbalken, wie am Rand eines Kartenblattes */
.mp-scale-plate { fill: #f4f5f2; opacity: .82; }
.mp-scale-a { fill: #3f4446; }
.mp-scale-b { fill: #f4f5f2; stroke: #3f4446; stroke-width: .6; vector-effect: non-scaling-stroke; }
.mp-scale-t { fill: #4c514e; font-family: var(--font-ui); font-size: 17px; font-weight: 500;
              text-anchor: middle; }
/* Damm und Steg, Freileitung */
.mp-edge { fill: none; stroke: #a9ada6; stroke-width: .8; vector-effect: non-scaling-stroke; }
.mp-wire { fill: none; stroke: #9aa09b; stroke-width: .7; stroke-dasharray: 9 4 1.5 4;
           vector-effect: non-scaling-stroke; }
/* Hauptstrassen mit dunklem Saum und hellem Kern — der Zug, an dem man eine
   Landeskarte erkennt. Erst alle Saeume, dann alle Kerne, sonst schneiden
   sich die Strassen an den Kreuzungen gegenseitig auf. */
.mp-r4 { stroke: #b3b8b2; stroke-width: .7; stroke-dasharray: 5 3.4; stroke-linecap: butt; }
.mp-r3 { stroke: #b1b6af; stroke-width: .95; }
.mp-r2c { stroke: #8a908a; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.mp-r2  { stroke: #fbfbfa; stroke-width: 1; stroke-linecap: round; stroke-linejoin: round; }
.mp-r1c { stroke: #3f4446; stroke-width: 3.4; stroke-linecap: round; stroke-linejoin: round; }
.mp-r1  { stroke: #ffffff; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.mp-blds path { fill: #25282a; }
.mp-lbl {
  fill: #4c514e; font-family: var(--font-ui); font-size: 21px; font-weight: 500;
  letter-spacing: .04em;
  /* Ohne Saum verschwindet die Schrift in den schwarzen Haeusern. */
  paint-order: stroke fill; stroke: #f1f2ef; stroke-width: 2.6; stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.mp-lbl-lg { font-size: 32px; letter-spacing: .01em; fill: #2b2f31; font-weight: 400; stroke-width: 3.4; }
/* Gewaessernamen stehen auf der Landeskarte blau und kursiv. */
.mp-lbl-water {
  fill: #7ba7bb; font-style: italic; font-weight: 400;
  text-anchor: middle; dominant-baseline: middle;
  /* Der Saum hat die Farbe des Sees, nicht die des Kartengrunds — sonst
     stuende ein weisser Rand um die Schrift mitten im Wasser. */
  stroke: #c9dce4; stroke-width: 1.4;
}
.mp-lbl-me { fill: #121415; font-weight: 600; text-anchor: middle; dominant-baseline: hanging; }
.mp-dot   { r: 10.5px; fill: var(--accent-light); stroke: #121415; stroke-width: 1.7; vector-effect: non-scaling-stroke; }
.mp-pulse { r: 11px; fill: none; stroke: var(--accent-light); stroke-width: 1.7; vector-effect: non-scaling-stroke; }

/* Startbild: die Flaeche, sonst nichts. */
.mp-relief, .mp-wood, .mp-scrub, .mp-park, .mp-sport, .mp-grass, .mp-farm,
.mp-yard, .mp-rock, .mp-wet, .mp-pool, .mp-water,
.mp-blds, .mp-lbl, .mp-pin { opacity: 0; }
.mp-stream, .mp-ct, .mp-cti, .mp-cth, .mp-r1, .mp-r2, .mp-r3,
.mp-r1c, .mp-r2c, .mp-edge { stroke-dasharray: 1; stroke-dashoffset: 1; }
.mp-r4, .mp-wire, .mp-ctlbl, .mp-scale { opacity: 0; }

/* `both` statt `forwards`: waehrend der Wartezeit gilt schon das erste Bild,
   und darin steht die Linie auf opacity 0. Sonst setzt der runde Abschluss
   eines noch nicht gezeichneten Strichs einen sichtbaren Punkt auf die Karte
   — bei 300 Strassen ein Sternenhimmel, bevor irgendetwas beginnt. */
.is-visible .mp-r4, .is-visible .mp-wire, .is-visible .mp-ctlbl,
.is-visible .mp-scale { animation: mp-in .55s ease var(--d, 0s) forwards; }
.is-visible .mp-stream, .is-visible .mp-ct, .is-visible .mp-cti,
.is-visible .mp-cth,
.is-visible .mp-r1, .is-visible .mp-r2, .is-visible .mp-r3,
.is-visible .mp-r1c, .is-visible .mp-r2c, .is-visible .mp-edge {
  animation: mp-draw var(--t, .5s) linear var(--d, 0s) both;
}
.is-visible .mp-relief, .is-visible .mp-wood, .is-visible .mp-scrub,
.is-visible .mp-park, .is-visible .mp-sport, .is-visible .mp-grass,
.is-visible .mp-farm, .is-visible .mp-yard, .is-visible .mp-rock,
.is-visible .mp-wet, .is-visible .mp-pool, .is-visible .mp-water,
.is-visible .mp-lbl { animation: mp-in .5s ease var(--d, 0s) forwards; }
.is-visible .mp-blds { animation: mp-blds-in .5s ease-out var(--d, 0s) forwards; }
.is-visible .mp-pin  { animation: mp-pin-in .52s cubic-bezier(.2, 1.5, .4, 1) var(--d, 0s) forwards; }
/* Ein Ring, dann Ruhe — ein dauerndes Pulsen zieht den Blick vom Text ab. */
.is-visible .mp-pulse { animation: mp-ping 1.2s ease-out calc(var(--d, 0s) + .14s) 1 both; }

@keyframes mp-draw { from { stroke-dashoffset: 1; opacity: 0; } 7% { opacity: 1; } to { stroke-dashoffset: 0; opacity: 1; } }
@keyframes mp-in   { to { opacity: 1; } }
@keyframes mp-blds-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@keyframes mp-pin-in  { from { opacity: 0; transform: translateY(-9px) scale(.55); } to { opacity: 1; transform: none; } }
@keyframes mp-ping    { from { transform: scale(.55); opacity: .8; } to { transform: scale(3.4); opacity: 0; } }

/* Die Schrift kann nicht in Bildschirmpunkten stehen, also waechst sie in
   zwei Stufen mit, wenn die Spalte schmaler wird. */
@media (max-width: 700px) {
  .mp-lbl:not(.mp-lbl-water) { font-size: 27px; }
  .mp-ctlbl { font-size: 24px; }
  .mp-scale-t { font-size: 22px; }
  .mp-lbl-lg { font-size: 38px; }
  .mp-dot { r: 13px; } .mp-pulse { r: 13.5px; }
}
@media (max-width: 480px) {
  .mp-lbl:not(.mp-lbl-water) { font-size: 35px; }
  .mp-ctlbl { font-size: 30px; }
  .mp-scale-t { font-size: 28px; }
  .mp-lbl-lg { font-size: 48px; }
  .mp-dot { r: 17px; } .mp-pulse { r: 17.5px; }
}

@media (prefers-reduced-motion: reduce) {
  .mp-relief, .mp-wood, .mp-scrub, .mp-park, .mp-sport, .mp-grass, .mp-farm,
  .mp-yard, .mp-rock, .mp-wet, .mp-pool, .mp-water,
  .mp-blds, .mp-lbl, .mp-pin { opacity: 1; }
  .mp-stream, .mp-ct, .mp-cti, .mp-cth, .mp-r1, .mp-r2, .mp-r3,
  .mp-r1c, .mp-r2c, .mp-edge { stroke-dashoffset: 0; }
  .mp-r4, .mp-wire, .mp-ctlbl, .mp-scale { opacity: 1; }
  .mp-pulse { display: none; }
  .map-frame *, .map-frame *::before { animation: none !important; }
}

/* Uneven on the live site: a 242px address block, then a 142px gap, then a
   207px contact block — not two equal halves. */
.contact-cols { display: grid; grid-template-columns: 242fr 207fr; gap: 142px; }
.contact-cols h3 { font-size: 26px; margin-bottom: 12px; }
.contact-cols a { display: block; color: var(--ink-soft); margin-bottom: 4px; }
.contact-cols a:hover { color: var(--accent); }

/* ---------- Termin buchen ----------
   Ein Formular heisst warten: schreiben, abschicken, und dann liegt der Ball
   zwei Tage bei uns. Wer reden will, soll sich eine Zeit aussuchen können und
   die Sache in dem Moment erledigt haben. Der Block steht deshalb ÜBER dem
   Formular, in derselben Spalte — das schnellere Angebot zuerst, das Formular
   als ruhige Alternative darunter.

   Solange in script.js keine Buchungsadresse hinterlegt ist, trägt er `hidden`
   und die Seite sieht aus wie vorher. Aktivieren ist eine Zeile. */
.booking-slot {
  grid-column: 2;
  outline: 1px solid rgba(255, 255, 255, 0.1);
  outline-offset: -1px;
  border-radius: 16px;
  padding: 24px 24px 22px;
}
.booking-slot h3 { font-family: var(--font-title); font-size: 24px; margin: 0 0 8px; }
.booking-slot p { color: var(--ink-soft); margin: 0 0 18px; max-width: 42ch; }
.booking-slot .btn { margin-right: 14px; }
.booking-or { color: var(--ink-soft); font-family: var(--font-ui); font-size: 14.5px; }
.contact-layout > .contact-form { grid-column: 2; }
/* Nur wenn der Block wirklich steht, reicht die Adresskarte über beide Zeilen. */
.contact-layout:has(.booking-slot:not([hidden])) .contact-info { grid-row: 1 / span 2; }
/* Auf dem Telefon steht alles untereinander, die Spaltenzuweisung entfällt. */
@media (max-width: 900px) {
  .booking-slot, .contact-layout > .contact-form { grid-column: auto; }
  .contact-layout:has(.booking-slot:not([hidden])) .contact-info { grid-row: auto; }
}
@media (max-width: 560px) {
  .booking-slot { padding: 20px 18px; }
  .booking-slot .btn { display: block; text-align: center; margin: 0 0 12px; }
  .booking-or { display: block; text-align: center; }
}

/* ---------- Legal / terms ---------- */
.legal-intro { max-width: 62ch; margin-bottom: 48px; }
.legal-section { border-top: 1px solid var(--line); padding: 28px 0; }
.legal-section h3 { font-size: 22px; margin-bottom: 12px; }
.legal-section p { max-width: 75ch; }

/* ---------- Section rhythm ---------- */
.section { padding-top: var(--section-pad); }
.section-head { margin-bottom: 40px; }

/* ---------- Responsive for new components ---------- */
@media (max-width: 900px) {
  .package-grid { grid-template-columns: 1fr; }
  .package-grid .package-card { aspect-ratio: auto; min-height: 320px; }
  .package-2col { grid-template-columns: 1fr; }
  .case-grid { grid-template-columns: 1fr 1fr; }
  .faq-grid { grid-template-columns: 1fr; }
  .stats-grid { grid-template-columns: 1fr 1fr; }
  .contact-cols { grid-template-columns: 1fr; }
  .contact-layout { grid-template-columns: 1fr; gap: 40px; }
}
@media (max-width: 900px) {
  /* Three across needs the desktop measure; below it, two, then one. */
  .testi-card { flex-basis: calc((100% - 24px) / 2); }
}
@media (max-width: 700px) {
  .case-grid { grid-template-columns: 1fr; }
}
/* Auf dem Telefon stehen zwei Stimmen übereinander — volle Breite, dafür halb
   so hoch. Beide zusammen sind ein Bild, und weiter geht es zur Seite.

   Vorher rollte der Streifen selbst senkrecht. Das war die Falle: eine
   Wischbewegung nach unten landete im Streifen statt auf der Seite, und weil
   das Karussell für den Endlos-Lauf Kopien anlegt, scrollte man minutenlang
   durch dieselben fünf Stimmen, statt bei "Our Services" anzukommen.

   Jetzt ist der Streifen ein Raster mit zwei Zeilen, das spaltenweise füllt:
   Karte 1 und 2 stehen übereinander, 3 und 4 in der nächsten Spalte. Er rollt
   nur noch waagerecht — senkrecht gibt es dort nichts zu holen, also gibt der
   Browser jede Abwärtsbewegung an die Seite weiter. */
@media (max-width: 640px) {
  .testi-viewport { overflow: hidden; padding: 0 20px; }
  .testi-track {
    display: grid;
    grid-auto-flow: column;
    grid-template-rows: repeat(2, 232px);
    grid-auto-columns: 100%;
    gap: 14px;
    overflow-x: auto; overflow-y: hidden;
    /* Am Ende des Streifens soll nicht die Seite seitwärts mitziehen. */
    overscroll-behavior-x: contain;
    /* Die Einrastpunkte liegen genau auf den Spaltenanfängen, also dort, wo
       auch das Karussell hinschiebt — anders als in der senkrechten Fassung
       steuern die beiden hier nicht gegeneinander. */
    scroll-snap-type: x mandatory;
    padding-bottom: 0;
  }
  .testi-card { width: auto; height: auto; scroll-snap-align: start; }
  .testi-quote { font-size: 15px; line-height: 1.45; padding: 18px 18px 0; }
  .testi-person { padding: 18px; gap: 10px; }
  .testi-person img { width: 34px; height: 34px; }
  .testi-person strong { font-size: 13px; }
  .testi-person span { font-size: 10px; line-height: 1.3; }
  /* Die Pfeile bleiben: sie blättern zum nächsten Paar. */
  .testi-head .carousel-nav { display: flex; }
}
@media (max-width: 560px) {
  .stats-grid { grid-template-columns: 1fr; }
}


/* =========================================================
   CASE-STUDY DETAIL PAGES (case-studies/<slug>/)
   ========================================================= */
a.case-card { display: block; color: inherit; text-decoration: none; }
.cs-breadcrumb { text-align: center; margin: 0 0 8px; }
.cs-breadcrumb a { color: var(--text-muted, #9ab29b); text-decoration: none; font-size: 14px; }
.cs-breadcrumb a:hover { text-decoration: underline; }
.cs-watch { text-align: center; letter-spacing: .02em; margin: 24px 0 12px; }
.cs-links { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-bottom: 32px; }
.cs-hero { margin: 0 auto 40px; max-width: 860px; }
.cs-hero video { width: 100%; border-radius: 16px; display: block; }
.cs-body { max-width: 760px; margin: 0 auto; }
.cs-body .h2 { margin: 40px 0 16px; }
.cs-body p { margin: 0 0 16px; line-height: 1.7; }
.cs-lede { margin: 24px 0 16px; font-size: 1.35rem; line-height: 1.45; }
/* Die Zahlen stehen in der 760px-Textspalte, nicht über die ganze Breite:
   vier nebeneinander drängen sich dort, zwei atmen. Die Ziffern etwas kleiner
   als im Statistik-Block der Startseite, damit "+21.7%" in seine Spalte passt.
   Unter 560px greift die bestehende Regel und stellt sie untereinander. */
.cs-body .stats-grid { grid-template-columns: 1fr 1fr; gap: 28px 40px; margin: 0 0 32px; }
.cs-body .stat-num { font-size: 42px; }
.cs-body .stat-num sup { font-size: 22px; }
.cs-body .stat h4 { margin: 4px 0 0; color: var(--ink-soft); font-weight: 400; }
@media (max-width: 560px) {
  .cs-body .stats-grid { grid-template-columns: 1fr; gap: 22px; }
}
.case-card-text { aspect-ratio: 16/10; display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.06); border-radius: 12px; }
.case-card-text span { font-family: var(--font-title); font-size: 1.3rem; opacity: .85; }

/* =========================================================
   SERVICES — Leistungen, nach Wichtigkeit gestaffelt
   Die Kartengrösse trägt die Rangfolge: eine grosse Karte für das,
   womit die meisten starten, dann zwei, dann drei kleinere.
   ========================================================= */

/* Laufband unter dem Opener */
.svc-ticker {
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: 18px 0; overflow: hidden; white-space: nowrap;
  background: rgba(255, 255, 255, 0.02);
}
.svc-ticker-track { display: inline-flex; gap: 46px; animation: svc-slide 42s linear infinite; will-change: transform; }
.svc-ticker span {
  font-family: var(--font-ui); font-size: 13px; font-weight: 500;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--ink-soft);
}
.svc-ticker span::before { content: "\25C6"; color: var(--accent); margin-right: 46px; font-size: 9px; vertical-align: middle; }
@keyframes svc-slide { to { transform: translateX(-50%); } }

.tier { display: grid; gap: 20px; margin-bottom: 20px; }
.tier-1 { grid-template-columns: 1fr; }
.tier-2 { grid-template-columns: repeat(3, 1fr); }
/* Sieben Leistungen: die kleinste Reihe trägt vier Karten. */
.tier-3 { grid-template-columns: repeat(4, 1fr); }

.svc {
  position: relative; display: flex; flex-direction: column; overflow: hidden;
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid var(--line); border-radius: var(--radius);
  transition: border-color .4s ease, transform .5s cubic-bezier(.16,1,.3,1), background .4s ease;
}
.svc:hover { transform: translateY(-6px); border-color: rgba(137, 184, 174, 0.42); background: rgba(255, 255, 255, 0.055); }

.svc-media { position: relative; overflow: hidden; background: #000; }
.svc-media video, .svc-media img {
  width: 100%; height: 100%; object-fit: cover; transform: scale(1.02);
  transition: transform 1s cubic-bezier(.16,1,.3,1); filter: saturate(.92) contrast(1.05);
}
.svc:hover .svc-media video, .svc:hover .svc-media img { transform: scale(1.07); }
/* Zwei Clips in einem Rahmen: der erste läuft zu Ende, dann übernimmt der
   zweite — dieselbe Reihenfolge, in der an dem Tag gefilmt wurde. Beide liegen
   übereinander, sichtbar ist immer nur der laufende. Die Transform-Überblendung
   muss hier mitgeschrieben werden, sonst fiele die Hover-Fahrt weg. */
[data-sequence] video {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity .5s ease, transform 1s cubic-bezier(.16,1,.3,1);
}
[data-sequence] video.is-playing { opacity: 1; }
.svc-media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(14, 15, 17, 0.1) 0%, rgba(14, 15, 17, 0.72) 100%);
}

/* ---------- Das Mosaik ----------
   Auf der Startseite zeigt die Teaser-Karte «Content Produktion» dasselbe
   Material wie die Leistungskarte, nur anders angeordnet: vier Kacheln,
   jede mit zwei Clips, die im Wechsel umschneiden. Die Kacheln sind um
   0.3s gegeneinander versetzt, also schneidet alle 0.3 Sekunden eine —
   acht Aufnahmen in zweieinhalb Sekunden, ohne dass es flimmert.
   Die Videos laden erst, wenn die Karte ins Bild kommt (preload="none"
   plus der Beobachter im Skript); die Startseite lädt dadurch nichts davon
   im Voraus. Blitz und Unschärfe sind dieselben wie im Mix. */
.mosaic {
  position: absolute; inset: 0; display: grid;
  grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 2px;
  background: #000;
}
.mosaic-tile {
  position: relative; overflow: hidden; min-width: 0;
  animation: mix-blur 1.2s cubic-bezier(.2,.8,.3,1) infinite;
}
.mosaic-tile:nth-child(2) { animation-delay: -.3s; }
.mosaic-tile:nth-child(3) { animation-delay: -.6s; }
.mosaic-tile:nth-child(4) { animation-delay: -.9s; }
.mosaic-tile video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  animation: mix-cut-third 3.6s steps(1, end) infinite;
}
.mosaic-tile video:nth-child(2) { animation-name: mix-cut-third-b; }
.mosaic-tile video:nth-child(3) { animation-name: mix-cut-third-c; }
.mosaic-tile:nth-child(2) video { animation-delay: -.3s; }
.mosaic-tile:nth-child(3) video { animation-delay: -.6s; }
.mosaic-tile:nth-child(4) video { animation-delay: -.9s; }
/* Drei statt zwei pro Kachel: zwölf Aufnahmen, dieselbe Zahl wie auf der
   Leistungskarte, und jede Kachel bleibt bei 1.2s pro Clip. */
@keyframes mix-cut-third   { 0% { opacity: 1; } 33.34% { opacity: 0; } }
@keyframes mix-cut-third-b { 0% { opacity: 0; } 33.34% { opacity: 1; } 66.67% { opacity: 0; } }
@keyframes mix-cut-third-c { 0% { opacity: 0; } 66.67% { opacity: 1; } }
.mosaic-tile::after {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background:
    radial-gradient(130% 70% at 50% 40%, rgba(168, 218, 207, .32), rgba(168, 218, 207, 0) 70%),
    linear-gradient(180deg, rgba(168, 218, 207, .2), rgba(168, 218, 207, 0) 45%);
  mix-blend-mode: screen; opacity: 0;
  animation: mix-flash 1.2s ease-out infinite;
  animation-delay: inherit;
}
@media (prefers-reduced-motion: reduce) {
  .mosaic-tile, .mosaic-tile video, .mosaic-tile::after { animation: none; }
  .mosaic-tile { filter: none; }
  .mosaic-tile::after { opacity: 0; }
  .mosaic-tile video:nth-child(2) { opacity: 0; }
}

/* ---------- Der Mix ----------
   Drei Streifen nebeneinander, in jedem zwei Clips, die im Sekundentakt
   umschneiden: sechs Aufnahmen aus einem Drehalltag, die nie stillstehen.
   Jeder Schnitt kommt mit einem kurzen Aufblitzen in Mint und einer Unschärfe,
   die sofort aufklart — der Effekt, der die Farbe der Marke ins Bild trägt,
   ohne dass ein Filter dauerhaft darüberliegt.

   Die Takte: 3s Schnittzyklus (1.5s pro Clip), 1.5s Blitz- und Unschärfezyklus
   — sie passen ineinander, darum sitzt jeder Blitz auf einem Schnitt. Die drei
   Streifen laufen um eine halbe Sekunde versetzt (negative Verzögerung, damit
   sie nicht erst warten), so schneidet irgendwo auf der Karte alle 0.5s etwas. */
.mix { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px; background: #000; }
.mix-cell {
  position: relative; overflow: hidden; min-width: 0;
  animation: mix-blur 1.5s cubic-bezier(.2,.8,.3,1) infinite;
}
.mix-cell:nth-child(2) { animation-delay: -.5s; }
.mix-cell:nth-child(3) { animation-delay: -1s; }
/* Vier Clips pro Streifen, jeder 1.5s: der Zyklus dauert 6s und jeder Clip
   hat sein Viertel. Zwölf Aufnahmen laufen so in sechs Sekunden durch — mit
   neun kam dieselbe Aufnahme spürbar oft wieder. Die 1.5s pro Clip bleiben,
   damit die Unschärfe (mix-blur, 1.5s) weiter auf den Schnitt fällt. */
.mix-cell video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  animation: mix-cut-a 6s steps(1, end) infinite;
}
.mix-cell video:nth-child(2) { animation-name: mix-cut-b; }
.mix-cell video:nth-child(3) { animation-name: mix-cut-c; }
.mix-cell video:nth-child(4) { animation-name: mix-cut-d; }
.mix-cell:nth-child(2) video { animation-delay: -.5s; }
.mix-cell:nth-child(3) video { animation-delay: -1s; }
@keyframes mix-cut-a { 0% { opacity: 1; } 25% { opacity: 0; } }
@keyframes mix-cut-b { 0% { opacity: 0; } 25% { opacity: 1; } 50% { opacity: 0; } }
@keyframes mix-cut-c { 0% { opacity: 0; } 50% { opacity: 1; } 75% { opacity: 0; } }
@keyframes mix-cut-d { 0% { opacity: 0; } 75% { opacity: 1; } }
/* Die Unschärfe sitzt auf dem Streifen, nicht auf dem Video: so wird das
   Aufblitzen gleich mitgeweicht und wirkt als Schein, nicht als Rechteck. */
@keyframes mix-blur {
  0%       { filter: blur(9px) saturate(1.6) brightness(1.18); }
  16%      { filter: blur(1px) saturate(1.05) brightness(1.02); }
  30%, 100% { filter: blur(0) saturate(1) brightness(1); }
}
/* Der Schein selbst: ein Mintfeld, das im Schnitt aufleuchtet und weggeht. */
.mix-cell::after {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background:
    radial-gradient(130% 70% at 50% 50%, rgba(168, 218, 207, .55), rgba(168, 218, 207, 0) 72%),
    linear-gradient(180deg, rgba(168, 218, 207, .3), rgba(168, 218, 207, 0) 55%);
  mix-blend-mode: screen; opacity: 0;
  animation: mix-flash 1.5s ease-out infinite;
  animation-delay: inherit;
}
@keyframes mix-flash { 0% { opacity: .9; } 10% { opacity: .35; } 26%, 100% { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .mix-cell, .mix-cell video, .mix-cell::after { animation: none; }
  .mix-cell video:nth-child(n+2) { opacity: 0; }
  .mix-cell { filter: none; }
  .mix-cell::after { opacity: 0; }
  .mix-cell video { opacity: 0; }
  .mix-cell video:first-child { opacity: 1; }
}

.svc-body { position: relative; z-index: 2; padding: 32px; display: flex; flex-direction: column; flex: 1; }
/* Statt einer Nummer trägt jede Leistung eine Etappe des Aufstiegs. Als
   grosses Umrisswort stand sie dem Titel im Weg — zwei Zeilen in derselben
   Schrift, fast gleich gross, ohne erkennbare Rangfolge. Jetzt ist die Etappe
   eine leise Marke über dem Titel: klein, gesperrt, in Akzentfarbe, mit einem
   kurzen Strich als Ausklang. So ist der Titel wieder der Titel. */
.svc .svc-label {
  font-family: var(--font-display); text-transform: uppercase;
  letter-spacing: 0.22em; line-height: 1;
  color: var(--accent); margin-bottom: 12px;
  display: flex; align-items: center; gap: 12px;
  transition: color .4s ease;
}
.svc .svc-label::after {
  content: ""; flex: 0 0 auto; width: 34px; height: 1px;
  background: currentColor; opacity: .5;
}
.svc:hover .svc-label { color: var(--accent-light); }
.svc h3 {
  font-family: var(--font-display); font-weight: 400; text-transform: uppercase;
  line-height: 1.02; letter-spacing: 0.01em; overflow-wrap: break-word; margin: 0;
}
.svc .kicker {
  font-family: var(--font-ui); font-size: 11.5px; font-weight: 600; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--accent); margin: 0 0 12px;
}
.svc ul { list-style: none; margin: 20px 0 0; padding: 0; }
.svc li { position: relative; padding-left: 20px; color: #c7cbc9; font-size: 15px; margin-bottom: 8px; line-height: 1.5; }
.svc li:last-child { margin-bottom: 0; }
.svc li::before { content: ""; position: absolute; left: 0; top: 11px; width: 9px; height: 1px; background: var(--accent); }

.tier-1 .svc { flex-direction: row; min-height: 620px; align-items: stretch; }
.tier-1 .svc-media { flex: 0 0 42%; }
.tier-1 .svc-media video { object-position: 28% center; }
/* Der Streifen ist schmaler als das Video und schneidet rund ein Viertel der
   Breite weg. 28% legt dieses Fenster nach links — richtig für Aufnahmen, bei
   denen dort etwas steht. Wo das Motiv rechts sitzt, ist links nur Wand. */
.tier-1 .svc-media video.frame-right { object-position: 85% center; }
.tier-1 .svc-media::after { background: linear-gradient(90deg, rgba(14, 15, 17, 0) 40%, rgba(14, 15, 17, 0.85) 100%); }
.tier-1 .svc-body { flex: 1 1 auto; min-width: 0; padding: 52px 48px; justify-content: center; }
.tier-1 .svc-label { font-size: 16px; }
.tier-1 h3 { font-size: clamp(26px, 2.9vw, 42px); }
.tier-1 li { font-size: 16px; }

/* Feste Höhe hiess: 16:9-Material verliert links und rechts etwas. Ein festes
   Seitenverhältnis statt einer festen Höhe lässt einen Brandfilm ganz stehen —
   samt eingebrannter Bauchbinde, die sonst angeschnitten würde. */
.tier-2 .svc-media { aspect-ratio: 16 / 9; height: auto; }
.tier-2 .svc-label { font-size: 14px; }
.tier-2 h3 { font-size: clamp(21px, 1.8vw, 26px); }

.tier-3 .svc-media { height: 160px; }
.tier-3 .svc-body { padding: 26px; }
.tier-3 .svc-label { font-size: 13px; }
.tier-3 h3 { font-size: 21px; }
.tier-3 li { font-size: 14px; }

/* ---------- Ads & Paid Social ----------
   Für diese Leistung gibt es kein Filmmaterial, und gestelltes wäre gelogen.
   Die Karte zeigt stattdessen die Arbeit selbst, in drei Szenen à 2.5s, hart
   geschnitten wie das Durchklicken auf der Websites-Karte:
     1. die Reichweite läuft hoch, die Balken wachsen nach,
     2. die Kampagnenzeilen im Werbekonto, eine wird scharf geschaltet,
     3. was danach hereinkommt — ein Verkauf, ein Like, neue Follower.
   Alles CSS, 7.5s pro Runde. Alle Innenanimationen hängen an derselben
   7.5s-Schlaufe und wählen ihr Zeitfenster über Prozente, damit sie zur
   sichtbaren Szene passen; die Rückstellung fällt jeweils in eine Phase, in
   der die Szene ohnehin verdeckt ist. Die Zahlen sind Anschauung, keine
   Kennzahl dieses Hauses; Meta und Instagram stehen als Namen der Kanäle da,
   ohne Logo. */
@property --reach {
  syntax: "<integer>";
  initial-value: 128;
  inherits: true;
}
.ads { background: #0b0c0d; }
.ads::after { display: none; }
/* Bei jedem Schnitt fährt ein Lichtstreifen über die Fläche — der Kitt
   zwischen den drei Szenen, damit der Wechsel nicht nur ein Umschalten ist. */
.ads::before {
  content: ""; position: absolute; z-index: 4; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 42%, rgba(168, 218, 207, .16) 50%, transparent 58%);
  background-size: 260% 100%;
  animation: ads-sweep 2.5s cubic-bezier(.5,0,.2,1) infinite;
}
@keyframes ads-sweep { 0% { background-position: 130% 0; } 34%, 100% { background-position: -130% 0; } }
.ads-grid {
  position: absolute; inset: 0; opacity: .5;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 100% 26px, 32px 100%;
}
/* Jede Szene fährt langsam heran oder weg, während sie steht — derselbe
   Ken-Burns-Kniff wie auf der Websites-Karte. Der Ausschlag ist klein: es ist
   eine Oberfläche mit Text, die darf atmen, aber nicht wackeln. */
.ads-scene {
  position: absolute; inset: 0; z-index: 2; opacity: 0;
  animation: ads-scene 7.5s linear infinite, ads-zoom-in 7.5s ease-out infinite;
}
.ads-scene-1 { animation-delay: 0s; }
.ads-scene-2 { animation-delay: 2.5s; animation-name: ads-scene, ads-zoom-out; }
.ads-scene-3 { animation-delay: 5s; }
@keyframes ads-scene { 0%, 31% { opacity: 1; } 33%, 100% { opacity: 0; } }
@keyframes ads-zoom-in  { 0% { transform: scale(1); }    31%, 100% { transform: scale(1.06); } }
@keyframes ads-zoom-out { 0% { transform: scale(1.06); } 31%, 100% { transform: scale(1); } }

/* Szene 1 — Reichweite */
.ads-key {
  position: absolute; left: 18px; top: 20px;
  font-family: var(--font-ui); font-size: 9px; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase; color: var(--ink-soft);
}
.ads-count {
  position: absolute; left: 18px; top: 34px;
  font-family: var(--font-title); font-size: 30px; line-height: 1; color: var(--ink);
  animation: ads-count 7.5s cubic-bezier(.25,.85,.35,1) infinite;
}
/* counter() liest die animierte Zahl — deshalb erbt --reach (inherits: true),
   sonst sähe das Pseudoelement nur den Startwert. */
.ads-count::after { counter-reset: reach var(--reach); content: counter(reach) "K"; }
@keyframes ads-count { 0% { --reach: 42; } 17%, 100% { --reach: 128; } }
.ads-bars {
  position: absolute; left: 45%; right: 16px; bottom: 16px;
  height: 62px; display: flex; align-items: flex-end; gap: 5px;
}
.ads-bars i {
  flex: 1; border-radius: 2px 2px 0 0; transform-origin: bottom; transform: scaleY(.1);
  background: linear-gradient(180deg, var(--accent-light), rgba(137, 184, 174, .22));
  animation: ads-bar 7.5s cubic-bezier(.2,.85,.3,1) infinite;
}
.ads-bars i:nth-child(1) { --h: .26; animation-delay: .02s; }
.ads-bars i:nth-child(2) { --h: .4;  animation-delay: .07s; }
.ads-bars i:nth-child(3) { --h: .34; animation-delay: .12s; }
.ads-bars i:nth-child(4) { --h: .58; animation-delay: .17s; }
.ads-bars i:nth-child(5) { --h: .7;  animation-delay: .22s; }
.ads-bars i:nth-child(6) { --h: .86; animation-delay: .27s; }
.ads-bars i:nth-child(7) { --h: 1;   animation-delay: .32s; }
@keyframes ads-bar { 0% { transform: scaleY(.1); } 16%, 90% { transform: scaleY(var(--h, 1)); } 100% { transform: scaleY(.1); } }
/* Auf der Oberkante jedes Balkens sitzt ein Lichtpunkt, der kurz aufglüht,
   sobald der Balken steht. */
.ads-bars i::after {
  content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 2px;
  border-radius: 2px; background: var(--accent-light);
  box-shadow: 0 0 8px rgba(168, 218, 207, .9);
  opacity: 0; animation: ads-spark 7.5s ease-out infinite;
}
.ads-bars i { position: relative; }
@keyframes ads-spark { 0%, 12% { opacity: 0; } 18% { opacity: 1; } 30%, 100% { opacity: 0; } }

/* Szene 2 — das Werbekonto */
.ads-row {
  position: absolute; left: 14px; right: 14px;
  display: grid; grid-template-columns: 1fr auto auto; gap: 10px; align-items: center;
  font-family: var(--font-ui); font-size: 9.5px; color: var(--ink);
  padding: 7px 10px; border-radius: 7px;
  background: rgba(255, 255, 255, .045); border: 1px solid var(--line);
  opacity: 0; animation: ads-row 7.5s cubic-bezier(.16,1,.3,1) infinite;
}
.ads-row span:nth-child(2) { color: var(--ink-soft); }
.ads-row span:nth-child(3) { color: var(--accent-light); font-weight: 600; }
.ads-row-head {
  background: none; border: none; padding: 0 10px;
  font-size: 8px; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-soft);
}
.ads-row-head span { color: inherit !important; font-weight: 400 !important; }
.ads-scene-2 .ads-row:nth-child(1) { top: 18px; animation-delay: 0s; }
.ads-scene-2 .ads-row:nth-child(2) { top: 40px; animation-delay: .1s; }
.ads-scene-2 .ads-row:nth-child(3) { top: 78px; animation-delay: .2s; }
@keyframes ads-row {
  0% { opacity: 0; transform: translateY(7px); }
  9%, 90% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translateY(7px); }
}
.ads-live {
  display: inline-block; width: 5px; height: 5px; border-radius: 50%;
  background: var(--accent); margin-right: 6px; vertical-align: 1px;
  animation: ads-live 1.6s ease-in-out infinite;
}
@keyframes ads-live { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
/* Der Schalter geht in der Szene an: der Knopf fährt hinüber, die Bahn färbt. */
.ads-switch {
  position: absolute; right: 16px; bottom: 16px; width: 30px; height: 16px;
  border-radius: 999px; background: rgba(255, 255, 255, .12);
  animation: ads-switch-track 7.5s ease infinite;
}
.ads-switch i {
  position: absolute; top: 2px; left: 2px; width: 12px; height: 12px;
  border-radius: 50%; background: var(--ink);
  animation: ads-switch-knob 7.5s cubic-bezier(.34,1.56,.64,1) infinite;
}
@keyframes ads-switch-track { 0%, 12% { background: rgba(255, 255, 255, .12); } 18%, 100% { background: rgba(137, 184, 174, .55); } }
@keyframes ads-switch-knob { 0%, 12% { transform: none; } 18%, 100% { transform: translateX(14px); } }
/* Derselbe Play-Knopf, den die Seite unter den Cursor legt, drückt hier den
   Schalter — die Karte klickt sich selbst scharf. */
.ads-switch::after {
  content: ""; position: absolute; left: 50%; top: 50%; width: 26px; height: 26px;
  margin: -13px 0 0 -13px; border-radius: 50%;
  border: 1.5px solid var(--accent-light); background: rgba(168, 218, 207, .18);
  opacity: 0; animation: ads-tap 7.5s cubic-bezier(.16,1,.3,1) infinite;
}
@keyframes ads-tap {
  0%, 9% { opacity: 0; transform: scale(.5); }
  13%    { opacity: 1; transform: scale(1.05); }
  17%    { opacity: .9; transform: scale(.88); }
  24%, 100% { opacity: 0; transform: scale(1.35); }
}

/* Szene 3 — was hereinkommt */
.ads-pop {
  position: absolute; opacity: 0;
  font-family: var(--font-ui); font-size: 9.5px; font-weight: 600; letter-spacing: .04em;
  color: var(--accent-light); background: rgba(137, 184, 174, .13);
  border: 1px solid rgba(137, 184, 174, .32); border-radius: 999px;
  padding: 3px 9px; white-space: nowrap;
  animation: ads-pop 7.5s ease-out infinite;
}
.ads-pop-1 { left: 18px; bottom: 26px; animation-delay: 0s; }
.ads-pop-2 { right: 26px; top: 22px; animation-delay: .3s; }
.ads-pop-3 { left: 38%; top: 52px; animation-delay: .6s; }
.ads-pop-4 { right: 20px; bottom: 20px; animation-delay: .9s; }
.ads-pop-1::before, .ads-pop-4::before {
  content: ""; position: absolute; inset: -7px; border-radius: 999px;
  border: 1px solid rgba(168, 218, 207, .5);
  opacity: 0; animation: ads-ring 7.5s ease-out infinite; animation-delay: inherit;
}
@keyframes ads-ring {
  0%, 3% { opacity: 0; transform: scale(.6); }
  6%     { opacity: .8; }
  18%, 100% { opacity: 0; transform: scale(1.9); }
}
@keyframes ads-pop {
  0% { opacity: 0; transform: translateY(10px) scale(.92); }
  4% { opacity: 1; transform: none; }
  16% { opacity: 1; transform: translateY(-3px); }
  22%, 100% { opacity: 0; transform: translateY(-14px); }
}

@media (prefers-reduced-motion: reduce) {
  .ads::before, .ads-scene, .ads-count, .ads-bars i, .ads-bars i::after,
  .ads-row, .ads-live, .ads-switch, .ads-switch::after, .ads-switch i,
  .ads-pop, .ads-pop::before { animation: none; transform: none; }
  .ads-scene-1 { opacity: 1; }
  .ads-scene-2, .ads-scene-3 { opacity: 0; }
  .ads-bars i { transform: scaleY(var(--h, 1)); }
}

/* ---------- Strategy & Audit ----------
   Auch hier gab es nur einen schwachen Clip. Die Karte heisst Compass, also
   zeigt sie einen: die Nadel sucht, schwingt über das Ziel hinaus und kommt
   zur Ruhe — und während sie steht, hakt sich die Liste ab, Punkt für Punkt.
   6 Sekunden pro Runde. */
.plan { background: #0b0c0d; }
.plan::after { display: none; }
.plan-compass {
  position: absolute; left: 26px; top: 50%; width: 74px; height: 74px; margin-top: -37px;
  border-radius: 50%; border: 1px solid rgba(168, 218, 207, .35);
  box-shadow: inset 0 0 22px rgba(168, 218, 207, .1);
}
/* Die Teilstriche der Rose: vier Linien, aus zwei Verläufen gezeichnet. */
.plan-compass::before {
  content: ""; position: absolute; inset: 9px; border-radius: 50%;
  background:
    linear-gradient(var(--line) 1px, transparent 1px) center / 100% 50% no-repeat,
    linear-gradient(90deg, var(--line) 1px, transparent 1px) center / 50% 100% no-repeat;
  opacity: .8;
}
/* Die Nadel: ein Dreieck, das sich um die Mitte dreht. */
.plan-compass i {
  position: absolute; left: 50%; top: 50%; width: 0; height: 0; margin: -26px 0 0 -5px;
  border-left: 5px solid transparent; border-right: 5px solid transparent;
  border-bottom: 26px solid var(--accent-light);
  transform-origin: 50% 100%;
  animation: plan-needle 6s cubic-bezier(.34,1.4,.5,1) infinite;
}
.plan-compass::after {
  content: ""; position: absolute; left: 50%; top: 50%; width: 6px; height: 6px;
  margin: -3px 0 0 -3px; border-radius: 50%; background: var(--ink);
}
@keyframes plan-needle {
  0%   { transform: rotate(-128deg); }
  22%  { transform: rotate(24deg); }
  32%  { transform: rotate(-9deg); }
  40%, 88% { transform: rotate(0deg); }
  100% { transform: rotate(-128deg); }
}
.plan-north {
  position: absolute; left: 26px; top: 50%; width: 74px; margin-top: -58px;
  text-align: center; font-family: var(--font-ui); font-size: 8px; font-weight: 600;
  letter-spacing: .22em; text-transform: uppercase; color: var(--accent);
  opacity: 0; animation: plan-north 6s ease-out infinite;
}
@keyframes plan-north { 0%, 38% { opacity: 0; } 46%, 88% { opacity: 1; } 100% { opacity: 0; } }

.plan-list {
  position: absolute; left: 120px; right: 18px; top: 50%; margin: 0; transform: translateY(-50%);
  padding: 0; list-style: none;
}
.plan-list li {
  position: relative; padding-left: 20px; margin-bottom: 9px;
  font-family: var(--font-ui); font-size: 10.5px; color: var(--ink);
  opacity: 0; animation: plan-item 6s cubic-bezier(.16,1,.3,1) infinite;
}
.plan-list li:last-child { margin-bottom: 0; }
.plan-list li:nth-child(1) { animation-delay: .1s; }
.plan-list li:nth-child(2) { animation-delay: .5s; }
.plan-list li:nth-child(3) { animation-delay: .9s; }
/* Der Haken wird gezeichnet, nicht eingeblendet — zwei Striche, die aus dem
   Nichts wachsen. */
.plan-list li::before {
  content: ""; position: absolute; left: 1px; top: 3px; width: 9px; height: 5px;
  border-left: 1.5px solid var(--accent-light); border-bottom: 1.5px solid var(--accent-light);
  transform-origin: left bottom; transform: rotate(-45deg) scaleX(0);
  animation: plan-tick 6s cubic-bezier(.16,1,.3,1) infinite;
  animation-delay: inherit;
}
@keyframes plan-item { 0%, 40% { opacity: 0; transform: translateX(-6px); } 50%, 90% { opacity: 1; transform: none; } 100% { opacity: 0; } }
@keyframes plan-tick { 0%, 52% { transform: rotate(-45deg) scaleX(0); } 62%, 90% { transform: rotate(-45deg) scaleX(1); } 100% { transform: rotate(-45deg) scaleX(0); } }

@media (prefers-reduced-motion: reduce) {
  .plan-compass i, .plan-north, .plan-list li, .plan-list li::before { animation: none; }
  .plan-compass i { transform: rotate(0deg); }
  .plan-north, .plan-list li { opacity: 1; transform: none; }
  .plan-list li::before { transform: rotate(-45deg) scaleX(1); }
}

/* ---------- Websites ----------
   Die Karte erzählt eine kleine Geschichte in 7.5 Sekunden: erst das Zeichen
   der Marke, das angetippt wird und zwei Wellen schlägt — der Tropfen —, dann
   fährt die Kamera hindurch in die Seite hinein, und dort wird geklickt und
   gescrollt, sieben echte Aufnahmen lang. Bei jedem Klick blitzt derselbe
   Play-Knopf auf, den die Seite auch sonst unter den Cursor legt.

   Aufteilung der Runde: 0–2.25s Intro, 2.25–7.5s Seite, sieben Bilder à 0.75s.
   Alles hängt an derselben 7.5s-Schlaufe; wo etwas erst später beginnen soll,
   steht eine Verzögerung — ohne `backwards`, damit vorher der Grundzustand
   gilt und nicht der erste Keyframe. */
.web { background: #0b0c0d; }
.web::after { display: none; }

/* --- Intro: das Zeichen und der Tropfen --- */
.web-intro {
  position: absolute; inset: 0; z-index: 4; display: block;
  background: #0b0c0d;
  animation: web-intro 7.5s cubic-bezier(.5,0,.75,0) infinite;
}
@keyframes web-intro {
  0%, 24% { opacity: 1; transform: scale(1); }
  32%     { opacity: 0; transform: scale(2.6); }
  100%    { opacity: 0; transform: scale(2.6); }
}
.web-logo {
  position: absolute; left: 50%; top: 50%; width: 116px; height: 29px;
  margin: -14px 0 0 -58px;
  background: url("/assets/logo.svg") center / contain no-repeat;
  opacity: 0; animation: web-logo 7.5s cubic-bezier(.16,1,.3,1) infinite;
}
@keyframes web-logo {
  0%      { opacity: 0; transform: scale(.86); }
  6%      { opacity: 1; transform: scale(1); }
  10%     { transform: scale(.94); }   /* der Druck */
  14%, 24% { transform: scale(1); }
  100%    { opacity: 1; transform: scale(1); }
}
/* Zwei Wellen vom Druckpunkt aus — das Zeichen sitzt links im Wortbild. */
.web-wave {
  position: absolute; left: 50%; top: 50%; width: 22px; height: 22px;
  margin: -11px 0 0 -28px; border-radius: 50%;
  border: 1px solid rgba(168, 218, 207, .55);
  opacity: 0; animation: web-wave 7.5s cubic-bezier(.2,.7,.3,1) infinite;
}
.web-wave-2 { animation-delay: .16s; border-color: rgba(255, 255, 255, .3); }
@keyframes web-wave {
  0%, 9%  { opacity: 0; transform: scale(.4); }
  12%     { opacity: .9; }
  22%,100%{ opacity: 0; transform: scale(4.2); }
}

/* --- Die Seite --- */
.web-stage {
  position: absolute; inset: 0; display: block; opacity: 0;
  animation: web-stage 7.5s cubic-bezier(.16,1,.3,1) infinite;
}
@keyframes web-stage {
  0%, 24% { opacity: 0; transform: scale(1.32); }
  33%     { opacity: 1; transform: scale(1); }
  100%    { opacity: 1; transform: scale(1); }
}
.browser {
  position: relative; z-index: 2; height: 26px; display: flex; align-items: center; gap: 8px;
  padding: 0 10px; background: rgba(255, 255, 255, 0.05); border-bottom: 1px solid var(--line);
}
.dots i { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: rgba(255, 255, 255, 0.22); margin-right: 4px; }
.url {
  font-family: var(--font-ui); font-size: 10px; letter-spacing: 0.08em; color: var(--ink-soft);
  background: rgba(0, 0, 0, 0.4); border-radius: 999px; padding: 2px 10px;
}
.frames { position: absolute; inset: 26px 0 0 0; overflow: hidden; }
.frames img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: top center;
  opacity: 0;
  animation: svc-shot 7.5s linear infinite, svc-kb-in 7.5s ease-out infinite;
}
/* Jedes zweite Bild fährt andersherum und scrollt in die Gegenrichtung,
   sonst pumpt die ganze Reihe im selben Takt. */
.frames img:nth-child(even) { animation-name: svc-shot, svc-kb-out; }
.frames img:nth-child(1) { animation-delay: 2.25s; }
.frames img:nth-child(2) { animation-delay: 3s; }
.frames img:nth-child(3) { animation-delay: 3.75s; }
.frames img:nth-child(4) { animation-delay: 4.5s; }
.frames img:nth-child(5) { animation-delay: 5.25s; }
.frames img:nth-child(6) { animation-delay: 6s; }
.frames img:nth-child(7) { animation-delay: 6.75s; }
@keyframes svc-shot { 0% { opacity: 1; } 10% { opacity: 1; } 10.01% { opacity: 0; } 100% { opacity: 0; } }
@keyframes svc-kb-in {
  0%       { transform: scale(1) translateY(0); }
  10%,100% { transform: scale(1.12) translateY(-3.5%); }
}
@keyframes svc-kb-out {
  0%       { transform: scale(1.12) translateY(-3%); }
  10%,100% { transform: scale(1) translateY(0); }
}

/* --- Der Zeiger und sein Play-Knopf --- */
.pointer {
  position: absolute; z-index: 3; width: 12px; height: 12px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.9); box-shadow: 0 0 0 6px rgba(255, 255, 255, 0.18);
  opacity: 0;
  animation: svc-click 7.5s steps(1, end) infinite, web-pointer 7.5s linear infinite;
}
@keyframes web-pointer { 0%, 28% { opacity: 0; } 30%, 100% { opacity: 1; } }
/* Der Play-Knopf blitzt bei jedem Klick auf — eine eigene 0.75s-Schlaufe, die
   in die 7.5s der Karte genau zehnmal passt und darum nie aus dem Takt fällt.
   Während des Intros ist der Zeiger unsichtbar, dort sieht man ihn nicht. */
.pointer-play {
  position: absolute; left: 50%; top: 50%; width: 30px; height: 30px; margin: -15px 0 0 -15px;
  border-radius: 50%; border: 1.5px solid var(--accent-light);
  background: rgba(168, 218, 207, .16);
  animation: web-play .75s cubic-bezier(.16,1,.3,1) infinite;
}
.pointer-play::after {
  content: ""; position: absolute; left: 11px; top: 8px;
  border-left: 9px solid var(--accent-light);
  border-top: 6.5px solid transparent; border-bottom: 6.5px solid transparent;
}
@keyframes web-play {
  0%   { opacity: 0; transform: scale(.5); }
  16%  { opacity: 1; transform: scale(1.06); }
  34%  { opacity: .95; transform: scale(.9); }
  60%  { opacity: 0; transform: scale(1.3); }
  100% { opacity: 0; transform: scale(1.3); }
}
@keyframes svc-click {
  0%,   28% { left: 22%; top: 64%; }
  30%  { left: 22%; top: 64%; }
  40%  { left: 70%; top: 38%; }
  50%  { left: 38%; top: 72%; }
  60%  { left: 64%; top: 52%; }
  70%  { left: 30%; top: 44%; }
  80%  { left: 74%; top: 66%; }
  90%  { left: 46%; top: 34%; }
}

@media (prefers-reduced-motion: reduce) {
  .web-intro, .web-logo, .web-wave, .web-stage,
  .frames img, .pointer, .pointer-play { animation: none; }
  .web-intro, .web-wave, .pointer { opacity: 0; }
  .web-stage { opacity: 1; transform: none; }
  .frames img { opacity: 0; transform: none; }
  .frames img:first-child { opacity: 1; }
}

@media (max-width: 1000px) {
  .tier-1 .svc { flex-direction: column; min-height: 0; }
  .tier-1 .svc-media { height: 280px; flex: none; }
  .tier-1 .svc-media::after { background: linear-gradient(180deg, rgba(14, 15, 17, 0.1), rgba(14, 15, 17, 0.8)); }
  .tier-1 .svc-body { padding: 34px 30px; }
  .tier-2, .tier-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 700px) {
  .tier-2, .tier-3 { grid-template-columns: 1fr; }
  /* Ab Personal Branding stehen acht Karten untereinander, jede mit vier
     Punkten — das ist auf dem Telefon eine endlose Liste. Diese Karten zeigen
     nur noch einen Knopf; wer es genau wissen will, klappt ihn auf. */
  .svc.is-collapsible ul { display: none; }
  .svc.is-collapsible.is-open ul { display: flex; }
  .svc-more {
    display: inline-flex; align-items: center; gap: 8px; align-self: flex-start;
    margin-top: 16px; padding: 8px 4px 8px 0;
    font-family: var(--font-ui); font-size: 13px; font-weight: 500;
    color: var(--accent-light); background: none; border: 0; cursor: pointer;
  }
  .svc-more::after {
    content: ""; width: 7px; height: 7px; margin-left: 2px;
    border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform .3s ease;
  }
  .svc.is-open .svc-more::after { transform: rotate(-135deg) translate(-1px, -1px); }
}
@media (min-width: 701px) {
  .svc-more { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .svc-ticker-track, .frames img, .pointer { animation: none; }
  .frames img { opacity: 0; }
  .frames img:first-child { opacity: 1; }
  .pointer { display: none; }
}

/* ---------- Case-Filter ----------
   Die Kategorien folgen der Leistungsseite, damit ein Besucher den Case
   findet, der zu der Leistung passt, die ihn hergebracht hat. */
.case-filters {
  display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 28px;
}
.case-filter {
  font-family: var(--font-ui); font-size: 14px; color: var(--ink);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 999px; padding: 9px 18px; cursor: pointer;
  transition: background .2s ease, border-color .2s ease, color .2s ease;
}
.case-filter:hover { background: rgba(255, 255, 255, 0.09); }
.case-filter.is-active {
  background: var(--accent-light); border-color: var(--accent-light); color: #0e0f11;
}
/* a.case-card setzt display:block und schlägt damit das eingebaute
   [hidden] des Browsers — deshalb hier ausdrücklich ausblenden. */
.case-card[hidden] { display: none; }
.case-empty { margin-top: 12px; color: var(--ink-soft); }
@media (max-width: 560px) {
  .case-filter { font-size: 13px; padding: 8px 14px; }
}

/* Das Interview mit Mario wurde flach gedreht (Log-Profil, nicht gegradet).
   Eine milde Gradation im Browser reicht, damit die Karte nicht ausgewaschen
   neben den anderen steht — bewusst zurückhaltend, rund 25 %. */
.testi-card img.bg[src$="delfos-metallbau.jpg"] {
  filter: saturate(1.28) contrast(1.07) brightness(1.03);
}

/* ---------- Kategorie auf der Case-Karte ----------
   Dieselbe Form wie die Filter-Pillen vorher, aber als Auszeichnung:
   sie sagt, welche Leistung hinter dem Case steckt. */
/* Die Kategorie sitzt unter dem Bild im dunklen Teil der Karte, rechts unten:
   im Bild verdeckte sie einen Teil der Aufnahme. Eckig mit weichen Kanten,
   und sie schreibt sich beim Reinscrollen selbst — das Skript setzt vorher
   die Breite fest, damit der Kasten dabei nicht wächst. */
a.case-card, .case-card { display: flex; flex-direction: column; }
.case-card img, .case-card video { order: 1; }
.case-card h3 { order: 2; }
.case-card p { order: 3; }
.case-tag {
  order: 4; align-self: flex-end; margin-top: auto;
  font-family: var(--font-ui); font-size: 12.5px; font-weight: 600; line-height: 20px;
  letter-spacing: .01em;
  color: var(--accent-light);
  background: rgba(137, 184, 174, 0.10);
  border: 1px solid rgba(137, 184, 174, 0.34);
  border-radius: 8px; padding: 6px 12px;
  white-space: nowrap; pointer-events: none;
}
/* Der Cursor blinkt nur, solange geschrieben wird. */
.case-tag::after {
  content: "";
  display: inline-block; width: 1px; height: 13px;
  margin-left: 3px; vertical-align: -2px;
  background: var(--accent-light); opacity: 0;
}
.case-tag.is-typing::after { opacity: 1; animation: caret .8s steps(1) infinite; }
@keyframes caret { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

@media (max-width: 560px) {
  .case-tag { font-size: 11.5px; padding: 5px 10px; }
}

/* ---------- Pfeil auf den Weiter-Buttons ---------- */
.btn .arrow {
  display: inline-block; margin-left: 10px;
  transition: transform .2s ease;
}
.btn:hover .arrow { transform: translateX(4px); }

/* =========================================================
   BEWEGUNG — Überschriften, Linien, Helligkeit, Seitenwechsel
   Alles hängt an .is-visible, das der Beobachter im Skript setzt,
   und schaltet sich bei "Bewegung reduzieren" komplett ab.
   ========================================================= */

/* Überschriften steigen aus einer Maske. Das Skript legt den Inhalt jeder
   Überschrift in .rise-inner; .rise selbst ist die Blende davor. */
.rise { display: block; overflow: hidden; padding-bottom: 0.08em; margin-bottom: -0.08em; }
.rise-inner {
  display: block;
  transform: translateY(105%);
  transition: transform 1s cubic-bezier(.16, 1, .3, 1);
}
.is-visible > .rise > .rise-inner,
.rise.is-visible > .rise-inner { transform: translateY(0); }

/* Die Haarlinie unter einem Sektionskopf zieht sich beim Erscheinen auf. */
.section-head::after, .sec-head::after {
  content: ""; display: block; height: 1px; margin-top: 24px;
  background: var(--line);
  transform: scaleX(0); transform-origin: left center;
  transition: transform 1.2s cubic-bezier(.16, 1, .3, 1) .15s;
}
.section-head.is-visible::after, .sec-head.is-visible::after { transform: scaleX(1); }

/* Medien kommen dunkel herein und hellen auf, sobald die Karte steht. */
.case-card img, .case-card video { filter: brightness(.45); transition: filter 1.1s ease; }
.case-grid.is-visible .case-card img, .case-grid.is-visible .case-card video { filter: brightness(1); }
.svc .svc-media video { filter: brightness(.45) saturate(.92) contrast(1.05); }
.svc.is-visible .svc-media video { filter: saturate(.92) contrast(1.05); }
.package-card .bg { filter: saturate(.9) contrast(1.05) brightness(.5); transition: filter 1.1s ease; }
.package-grid.is-visible .package-card .bg { filter: saturate(.9) contrast(1.05) brightness(.92); }

/* ---------- Cases fast in Schwarzweiss ----------
   Die Cases liegen ganz entfärbt im Raster. Beim Hereinscrollen bekommen sie
   einen Rest Farbe von 15% — genug, dass man sieht, dass Farbe drinsteckt, zu
   wenig, als dass es dabei bleiben könnte. Erst der Cursor holt einer Karte
   die volle Farbe zurück, und genau dieser Sprung zeigt, dass die Karten auf
   einen reagieren. Geräte ohne Zeigegerät kennen kein
   Darüberfahren — dort bleiben die Videos farbig, sonst wäre die Farbe dort
   nie zu sehen. */
@media (hover: hover) {
  .case-card img, .case-card video { filter: brightness(.45) grayscale(1); }
  .case-grid.is-visible .case-card img,
  .case-grid.is-visible .case-card video {
    filter: brightness(1) grayscale(.85);
    transition: filter .6s ease;
  }

  .case-card:hover img, .case-card:hover video,
  .case-card:focus-visible img, .case-card:focus-visible video,
  .case-grid.is-visible .case-card:hover img,
  .case-grid.is-visible .case-card:hover video,
  .case-grid.is-visible .case-card:focus-visible img,
  .case-grid.is-visible .case-card:focus-visible video {
    filter: brightness(1) grayscale(0);
    transition: filter .45s ease;
  }
}
/* Ohne Cursor gibt es kein Darüberfahren. Auf Geräten ohne Zeiger entscheidet
   deshalb die Position: was in der Bildmitte steht, bekommt Farbe. Am Rechner
   bleibt es beim Darüberfahren — dort ist der Cursor die bessere Antwort. */
@media (hover: none) {
  .case-card img, .case-card video,
  .case-grid.is-visible .case-card img,
  .case-grid.is-visible .case-card video {
    filter: brightness(1) grayscale(.85); transition: filter .5s ease;
  }
  .case-grid .case-card.in-focus img,
  .case-grid .case-card.in-focus video,
  .case-grid.is-visible .case-card.in-focus img,
  .case-grid.is-visible .case-card.in-focus video { filter: brightness(1) grayscale(0); }
}

/* ---------- Die Cases auf der Startseite ----------
   Hier hängt die Farbe nicht an einer Schwelle, sondern am Weg: je näher die
   Karte der Bildmitte kommt, desto farbiger wird sie, und beim Weiterziehen
   geht die Farbe wieder. Den Wert rechnet das Skript und legt ihn als
   --gray auf die Karte.

   Am Rechner endet dieser Weg bei 15% Farbe, nicht bei voller Farbe: die
   letzten 85% gibt erst der Cursor her. Wer scrollt, sieht die Karten kurz
   anfarben und wieder verblassen — das ist der Hinweis, dass hier noch etwas
   zu holen ist. Auf dem Telefon gibt es keinen Cursor; dort bleibt es dabei,
   dass die Karte in der Bildmitte voll farbig wird. */
.case-grid-drift .case-card img,
.case-grid-drift .case-card video,
.case-grid-drift.is-visible .case-card img,
.case-grid-drift.is-visible .case-card video {
  filter: brightness(1) grayscale(var(--gray, .85));
  transition: filter .25s linear;
}
.case-grid-drift .case-card:hover img,
.case-grid-drift .case-card:hover video,
.case-grid-drift.is-visible .case-card:hover img,
.case-grid-drift.is-visible .case-card:hover video { filter: brightness(1) grayscale(0); }

/* Ein Druck auf eine Karte gibt nach, bevor die nächste Seite kommt. */
a.case-card:active, a.package-card:active, .btn:active { transform: scale(.985); }

/* Seitenwechsel: der neue Inhalt zoomt herein, der alte weicht zurück.
   Browser ohne View Transitions wechseln wie bisher. */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: vt-out .32s cubic-bezier(.4, 0, 1, 1) forwards; }
::view-transition-new(root) { animation: vt-in .5s cubic-bezier(.16, 1, .3, 1); }
@keyframes vt-out { to { opacity: 0; transform: scale(1.03); } }
@keyframes vt-in { from { opacity: 0; transform: scale(.982); } }

@media (prefers-reduced-motion: reduce) {
  .rise-inner { transform: none; }
  .section-head::after, .sec-head::after { transform: scaleX(1); }
  .case-card img, .case-card video { filter: grayscale(.85); }
  .package-card .bg { filter: saturate(.9) contrast(1.05) brightness(.92); }
  .svc .svc-media video { filter: saturate(.92) contrast(1.05); }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}

/* ---------- Neonring auf den Cases ----------
   Ein Lichtpunkt läuft beim Darüberfahren einmal um die Karte. Der Ring ist
   ein Kegelverlauf, aus dem eine Maske alles ausser einem Rahmen von 1.5px
   herausschneidet — so leuchtet nur die Kante, nicht die Fläche.
   Browser ohne @property zeigen den Ring ruhig statt umlaufend. */
@property --ring-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}
.case-card { position: relative; isolation: isolate; }
.case-card::before, .package-card .ring {
  content: ""; position: absolute; inset: -1px; z-index: 3; pointer-events: none;
  border-radius: inherit; padding: 1.5px;
  background: conic-gradient(
    from var(--ring-angle),
    rgba(168, 218, 207, 0) 0deg,
    rgba(168, 218, 207, 0) 200deg,
    var(--accent) 290deg,
    var(--accent-light) 340deg,
    rgba(168, 218, 207, 0) 360deg
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 0; transition: opacity .35s ease;
}
.case-card:hover::before, .case-card:focus-visible::before,
.package-card:hover .ring, .package-card:focus-visible .ring {
  opacity: 1;
  animation: ring-run 2.2s linear infinite;
}
@keyframes ring-run { to { --ring-angle: 360deg; } }

/* Ein zweiter, sehr weicher Schein darunter — das ist, was den Ring als Neon
   lesbar macht statt als gezeichnete Linie. */
.case-card::after {
  content: ""; position: absolute; inset: -1px; z-index: 2; pointer-events: none;
  border-radius: inherit;
  box-shadow: 0 0 24px rgba(137, 184, 174, 0.35);
  opacity: 0; transition: opacity .35s ease;
}
.case-card:hover::after { opacity: 1; }
.package-card { isolation: isolate; }
.package-card .ring { border-radius: 16px; box-shadow: 0 0 24px rgba(137, 184, 174, .28); }

@media (prefers-reduced-motion: reduce) {
  .case-card:hover::before, .package-card:hover .ring { animation: none; }
}

/* ---------- Klick-Zeichen ----------
   Ein Klick setzt für einen Moment den Play-Button der Marke an die Stelle,
   auf die gedrückt wurde: er erscheint, wird gedrückt und verschwindet,
   während die nächste Seite schon lädt. Der Zeiger selbst bleibt normal. */
.click-play {
  position: fixed; z-index: 999; width: 46px; height: 46px;
  margin: -23px 0 0 -23px; pointer-events: none;
  animation: click-play .42s cubic-bezier(.16, 1, .3, 1) forwards;
}
.click-play svg { display: block; width: 100%; height: 100%; }
@keyframes click-play {
  0%   { opacity: 0; transform: scale(.55); }
  28%  { opacity: 1; transform: scale(1.06); }
  52%  { transform: scale(.86); }
  72%  { opacity: .9; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.25); }
}
@media (prefers-reduced-motion: reduce) { .click-play { display: none; } }

/* ---------- Logo-Aufbau auf der Startseite ----------
   Das Zeichen fällt in die Mitte des Logofelds, staucht beim Aufsetzen,
   wird gedrückt — mit Wellen vom Druckpunkt — und wandert dann an seinen
   Platz, während die Buchstaben hinter ihm hervorkommen.

   Die Grafik liegt in zwei Dateien: Wortmarke ohne Zeichen, Zeichen allein,
   beide mit dem viewBox des Originals. Getrennt wird bei x=94 von 340 —
   mitten in der Lücke zwischen R und G. An der Dreieckskante (x=118) lag die
   Trennung zu weit rechts: das G ragt bis x=115 und wurde angeschnitten.
   Was zwischen Trennkante und Zeichen liegt, verdeckt ohnehin das Zeichen. */
.logo.anim { position: relative; display: block; width: 150px; height: 38px; }
.logo.anim span {
  position: absolute; inset: 0;
  background: url("/assets/logo-letters.svg") center / cover no-repeat;
  will-change: clip-path, transform;
}
.logo.anim .l { clip-path: inset(0 72.37% 0 0); animation: logo-wipe-l .7s cubic-bezier(.42, 0, .38, 1) .73s both; }
.logo.anim .r { clip-path: inset(0 0 0 27.63%); animation: logo-wipe-r .7s cubic-bezier(.42, 0, .38, 1) .73s both; }
.logo.anim .t {
  background-image: url("/assets/logo-mark.svg");
  transform-origin: 29.1% 50%;
  animation: logo-mark 1.4s both;
}
/* Alle Zeiten hier sind mit 1.4/1.5 skaliert: die Folge läuft eine
   Zehntelsekunde früher durch als ursprünglich, ohne dass sich das Verhältnis
   der Teile zueinander verschiebt — sonst setzt das Zeichen auf, bevor die
   Buchstaben es freigeben. Daher die krummen Werte. */
/* Zwei Wellen vom Druckpunkt — dünn, halbdurchsichtig, leicht versetzt. */
.logo.anim .w1, .logo.anim .w2 {
  background: none;
  left: 50%; top: 50%; right: auto; bottom: auto;
  width: 26px; height: 26px; margin: -13px 0 0 -13px;
  border: 1px solid rgba(168, 218, 207, .5);
  border-radius: 50%;
  opacity: 0;
  animation: logo-wave .89s cubic-bezier(.2, .7, .3, 1) .62s both;
}
.logo.anim .w2 { animation-delay: .72s; border-color: rgba(255, 255, 255, .32); }
@keyframes logo-wave {
  0%   { opacity: 0; transform: scale(.35); }
  18%  { opacity: .85; }
  100% { opacity: 0; transform: scale(3.1); }
}
/* Die Kanten der Buchstaben folgen dem Zeichen, während es nach links zieht. */
@keyframes logo-wipe-l {
  from { clip-path: inset(0 55.61% 0 44.39%); }
  to   { clip-path: inset(0 72.37% 0 0); }
}
@keyframes logo-wipe-r {
  from { clip-path: inset(0 44.39% 0 55.61%); }
  to   { clip-path: inset(0 0 0 27.63%); }
}
/* Fallen, Aufsetzen, Nachfedern, Druck, dann der Weg an den Platz. Beim
   Druck geht das Zeichen kurz dunkler und minim tiefer — so liest es sich
   als gedrückt und nicht bloss als kleiner. */
@keyframes logo-mark {
  0%   { opacity: 0; transform: translate(31.3px, -26px) scale(.92); animation-timing-function: cubic-bezier(.55, 0, .85, .2); }
  18%  { opacity: 1; transform: translate(31.3px, 4px) scale(1.1, .88); animation-timing-function: cubic-bezier(.2, 0, .2, 1); }
  27%  { transform: translate(31.3px, -5px) scale(.95, 1.06); animation-timing-function: cubic-bezier(.5, 0, .8, .3); }
  36%  { transform: translate(31.3px, 0) scale(1.02, .98); animation-timing-function: cubic-bezier(.2, 0, .3, 1); }
  43%  { transform: translate(31.3px, 0) scale(1); filter: brightness(1); animation-timing-function: cubic-bezier(.4, 0, .2, 1); }
  50%  { transform: translate(31.3px, 1.5px) scale(.82); filter: brightness(.62); animation-timing-function: cubic-bezier(.3, 0, .2, 1); }
  58%  { transform: translate(31.3px, 0) scale(1); filter: brightness(1); animation-timing-function: cubic-bezier(.42, 0, .38, 1); }
  100% { transform: translate(0, 0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .logo.anim .l, .logo.anim .r, .logo.anim .t { animation: none; }
  .logo.anim .w1, .logo.anim .w2 { display: none; }
}

