/* =========================================================
   dEVils-Nails – oeffentlicher Bereich
   Dunkles, app-artiges Layout mit hellem Tag-Schema (Sonnenstand).
   Tokens: tokens.css. Nur Systemschriften, keine externen Ressourcen.
   ========================================================= */

/* ---------- Basis ---------- */

[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  -moz-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 5.5rem;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  transition: background-color .35s, color .35s;
}

body.menu-open { overflow: hidden; }

main { flex: 1 0 auto; }

/* Weiche Farbflaechen im Hintergrund ... */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(60rem 42rem at 82% -10%, var(--glow-pink), transparent 62%),
    radial-gradient(46rem 36rem at 4% 14%, var(--glow-season), transparent 60%),
    linear-gradient(180deg, var(--bg-soft), var(--color-bg) 46%);
  pointer-events: none;
}

/* ---- Saison-Flug -----------------------------------------------------
   Zwoelf Lichtpunkte in der Farbe der Jahreszeit, die langsam durchs Bild
   ziehen. Bewusst keine Schneeflocken oder Blaetter: die Seite ist
   "teuflisch gut", nicht Bastelbogen -- es ist dieselbe Glanzlicht-Sprache
   wie beim Rest.

   Animiert werden NUR transform und opacity. Beides laeuft auf der
   Grafikkarte, ohne das Layout neu zu berechnen; zwoelf Elemente kosten
   damit auch auf einem aelteren Handy praktisch nichts. Kein blur(), das
   waere je Bild teuer -- der weiche Rand kommt aus einem Farbverlauf. */
.saison-flug {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

.saison-flug span {
  position: absolute;
  top: -10vh;
  left: var(--x);
  width: var(--s);
  height: var(--s);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--season-rgb), .5), rgba(var(--season-rgb), 0) 70%);
  opacity: 0;
  animation: saison-zug var(--t) linear var(--d) infinite;
  will-change: transform, opacity;
}

@keyframes saison-zug {
  0%   { transform: translate3d(0, 0, 0) scale(.85); opacity: 0; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { transform: translate3d(var(--drift), 122vh, 0) scale(1.15); opacity: 0; }
}

/* Zwoelf verschiedene Bahnen. Bewusst per nth-child statt inline im
   Template: das HTML bleibt sauber, und die Werte stehen dort, wo man sie
   beim Nachjustieren sucht. */
.saison-flug span:nth-child(1)  { --x: 6%;  --s: 7px; --t: 26s; --d: 0s;    --drift: 4vw; }
.saison-flug span:nth-child(2)  { --x: 17%; --s: 4px; --t: 34s; --d: -6s;   --drift: -3vw; }
.saison-flug span:nth-child(3)  { --x: 28%; --s: 9px; --t: 22s; --d: -14s;  --drift: 2vw; }
.saison-flug span:nth-child(4)  { --x: 36%; --s: 5px; --t: 30s; --d: -3s;   --drift: -5vw; }
.saison-flug span:nth-child(5)  { --x: 45%; --s: 6px; --t: 28s; --d: -19s;  --drift: 3vw; }
.saison-flug span:nth-child(6)  { --x: 53%; --s: 3px; --t: 38s; --d: -9s;   --drift: -2vw; }
.saison-flug span:nth-child(7)  { --x: 62%; --s: 8px; --t: 24s; --d: -22s;  --drift: 5vw; }
.saison-flug span:nth-child(8)  { --x: 70%; --s: 4px; --t: 32s; --d: -12s;  --drift: -4vw; }
.saison-flug span:nth-child(9)  { --x: 78%; --s: 6px; --t: 27s; --d: -26s;  --drift: 2vw; }
.saison-flug span:nth-child(10) { --x: 85%; --s: 5px; --t: 35s; --d: -16s;  --drift: -3vw; }
.saison-flug span:nth-child(11) { --x: 92%; --s: 7px; --t: 23s; --d: -30s;  --drift: 4vw; }
.saison-flug span:nth-child(12) { --x: 97%; --s: 3px; --t: 36s; --d: -7s;   --drift: -6vw; }

/* Ohne Jahreszeit gibt es nichts zu zeigen: in der Uebergangszeit ("basis")
   und wenn gar kein Attribut gesetzt ist, faellt die Schicht ganz weg. */
.saison-flug { display: none; }
html[data-season="fruehling"] .saison-flug,
html[data-season="sommer"] .saison-flug,
html[data-season="herbst"] .saison-flug,
html[data-season="winter"] .saison-flug { display: block; }

/* Fruehling und Sommer ziehen nach OBEN -- leicht statt fallend. Die Punkte
   sind rund, deshalb genuegt das Spiegeln der ganzen Schicht; dafuer braucht
   es keinen zweiten Bewegungsablauf. */
html[data-season="fruehling"] .saison-flug,
html[data-season="sommer"] .saison-flug { transform: scaleY(-1); }

/* Winter: kleiner und klarer, wie feiner Frost. */
html[data-season="winter"] .saison-flug span {
  background: radial-gradient(circle, rgba(var(--season-rgb), .62), rgba(var(--season-rgb), 0) 62%);
}

/* Herbst: eine Spur traeger und satter. */
html[data-season="herbst"] .saison-flug span {
  animation-duration: calc(var(--t) * 1.25);
  background: radial-gradient(circle, rgba(var(--season-rgb), .55), rgba(var(--season-rgb), 0) 72%);
}

/* ... und eine feine diagonale Schraffur (wie Pinselstriche, passend zum
   Logo), die nach unten ausblendet */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background-image: repeating-linear-gradient(-32deg, var(--line-strong) 0 1px, transparent 1px 22px);
  -webkit-mask-image: radial-gradient(120% 70% at 85% 0%, #000 5%, transparent 70%);
  mask-image: radial-gradient(120% 70% at 85% 0%, #000 5%, transparent 70%);
  opacity: .28;
  pointer-events: none;
}

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

h1, h2, h3, h4 { margin: 0 0 .6em; text-wrap: balance; }
p { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }

/* Tastatur-Fokus. Bewusst NICHT die Akzentfarbe: auf dem gefuellten
   Hauptbutton hat ein Akzent-Rahmen exakt die Buttonfarbe (gemessen 1.00:1)
   und ist damit nur noch in der 3px-Luecke daneben zu ahnen. */
:focus-visible {
  outline: 2px solid var(--fokus-ring);
  outline-offset: 3px;
  border-radius: 4px;
}

::selection { background: var(--color-accent); color: #fff; }

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip-link {
  position: fixed;
  top: .75rem;
  left: -120%;
  z-index: 100;
  padding: .7rem 1.1rem;
  border-radius: 999px;
  background: var(--color-accent);
  color: #fff;
  font-size: .85rem;
  font-weight: 700;
  text-decoration: none;
}
.skip-link:focus { left: .75rem; }

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

.icon { width: 1.1rem; height: 1.1rem; flex: none; }

/* ---------- Typografie-Bausteine ---------- */

.label {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: 0 0 1.2rem;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.label::before {
  content: "";
  width: 1.7rem;
  height: 1px;
  background: var(--accent-line);
}

/* Pinselstrich unter dem Akzentwort -- greift die Brush-Schrift des Logos auf */
.accent-word {
  display: inline-block;
  padding: 0 .04em .12em;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  color: var(--accent-ink);
  letter-spacing: -.01em;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 14' preserveAspectRatio='none'%3E%3Cpath d='M3 9c30-5 60-6 95-5 30 1 60 1 99-3' fill='none' stroke='%23e6197a' stroke-width='5' stroke-linecap='round' opacity='.85'/%3E%3C/svg%3E") no-repeat center bottom / 100% .32em;
}

.lead {
  max-width: 56ch;
  color: var(--color-text-muted);
  font-size: clamp(1.02rem, 1.15vw, 1.15rem);
  line-height: 1.72;
}

/* ---------- Kopfzeile ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 1px solid transparent;
  transition: background-color .3s, border-color .3s;
}
.site-header.is-stuck {
  background: var(--header-bg);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  backdrop-filter: blur(16px) saturate(1.4);
  border-bottom-color: var(--line);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 4.5rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  margin-right: auto;
  border-radius: 999px;
  text-decoration: none;
}
/* Feste Box: kein Layoutsprung, egal welches Logo hochgeladen wurde */
.brand-box {
  display: grid;
  place-items: center;
  width: 7.5rem;
  height: 3.25rem;
  padding: .25rem .5rem;
  border-radius: 999px;
  transition: background-color .3s, box-shadow .3s, transform .3s var(--ease);
}
.brand-box img { width: 100%; height: 100%; object-fit: contain; }
.brand:hover .brand-box { transform: translateY(-1px) scale(1.03); }
/* Im hellen Schema die Variante mit dunklen Buchstaben (LogoLightVariant),
   ohne Pille. Nur wenn zu einem Upload keine Variante existiert, bleibt die
   dunkle Pille als Rueckfall. */
.brand-box .logo-light { display: none; }
html[data-theme="light"] .brand-box.has-light .logo-dark { display: none; }
html[data-theme="light"] .brand-box.has-light .logo-light { display: block; }
html[data-theme="light"] .brand-box:not(.has-light) {
  background: var(--ink-dark);
  box-shadow: var(--shadow-md);
}

.site-nav {
  display: none;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 2rem);
}
.site-nav a {
  position: relative;
  padding: .4rem 0;
  color: var(--color-text-muted);
  font-size: .92rem;
  font-weight: 500;
  text-decoration: none;
  /* Ohne das bricht ausgerechnet "Über Evi" um -- als einziger Punkt mit
     Leerzeichen. Gemessen: 33 px breit, 60 px hoch, also zwei Zeilen mitten
     in einer einzeiligen Leiste. */
  white-space: nowrap;
  transition: color .2s;
}
/* ---- "Mehr" in der Leiste am Rechner ---------------------------------
   Acht Punkte plus Knopf waren zu viel: die Leiste wurde eng, und der
   einzige Punkt mit Leerzeichen brach um. Oben stehen jetzt die fuenf, die
   eine Kundin auf dem Weg zum Termin braucht; Blog, Glossar, TikTok und
   Empfehlungen liegen dahinter.

   <details>/<summary> statt eigener Klapp-Logik: oeffnet und schliesst ohne
   JavaScript, und die Tastatur kann es von Haus aus. */
.nav-mehr { position: relative; }

.nav-mehr > summary {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .4rem 0;
  color: var(--color-text-muted);
  font-size: .92rem;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
  transition: color .2s;
}
/* Das voreingestellte Dreieck entfernen -- wir setzen ein eigenes Zeichen. */
.nav-mehr > summary::-webkit-details-marker { display: none; }
.nav-mehr > summary::marker { content: ""; }
.nav-mehr > summary:hover,
.nav-mehr[open] > summary { color: var(--color-text); }
.nav-mehr > summary[aria-current="page"] { color: var(--color-text); }

.nav-mehr-pfeil { width: .85rem; height: .85rem; transition: transform .2s var(--ease); }
.nav-mehr[open] .nav-mehr-pfeil { transform: rotate(180deg); }

.nav-mehr-panel {
  position: absolute;
  top: calc(100% + .55rem);
  right: 0;
  z-index: 60;
  /* WICHTIG: standardmaessig versteckt. Ein "display" auf dem Kind eines
     <details> haengt die Voreinstellung des Browsers aus -- mit "display: grid"
     hier stand das Klappfeld auch im geschlossenen Zustand offen da. */
  display: none;
  gap: .1rem;
  min-width: 11rem;
  padding: .5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel-solid);
  box-shadow: var(--shadow-md);
}
.nav-mehr[open] .nav-mehr-panel { display: grid; }

.nav-mehr-panel a {
  padding: .55rem .7rem;
  border-radius: 10px;
  white-space: nowrap;
}
.nav-mehr-panel a:hover { background: var(--accent-soft); color: var(--color-text); }
/* Der Unterstrich der Hauptleiste passt im Klappfeld nicht. */
.nav-mehr-panel a::after { display: none; }

.site-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 2px;
  border-radius: 2px;
  background: var(--color-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .3s var(--ease);
}
.site-nav a:hover,
.site-nav a[aria-current="page"] { color: var(--color-text); }
.site-nav a:hover::after,
.site-nav a[aria-current="page"]::after { transform: scaleX(1); }

.header-actions { display: flex; align-items: center; gap: .6rem; }

.icon-btn {
  display: grid;
  place-items: center;
  width: 2.75rem;   /* 44px: Mindestgroesse fuer Daumen-Tipps */
  height: 2.75rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--color-text-muted);
  cursor: pointer;
  transition: color .2s, border-color .2s, transform .25s var(--ease), background-color .2s;
}
.icon-btn:hover { color: var(--color-text); border-color: var(--accent-line); transform: translateY(-1px); }
.icon-btn svg { width: 1.1rem; height: 1.1rem; }

.theme-toggle .icon-sun { display: none; }
.theme-toggle .icon-moon { display: block; }
html[data-theme="light"] .theme-toggle .icon-sun { display: block; }
html[data-theme="light"] .theme-toggle .icon-moon { display: none; }
.theme-toggle svg { transition: transform .5s var(--ease); }
.theme-toggle:hover svg { transform: rotate(25deg); }

.header-cta { min-height: 2.75rem; padding: .35rem 1.05rem; font-size: .86rem; }

.menu-toggle { display: grid; }

/* ---------- Mobiles Menue (Vollbild) ---------- */

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  padding: env(safe-area-inset-top) var(--gutter) calc(1.25rem + env(safe-area-inset-bottom));
  /* Der Farbschein ist Teil des Hintergrunds -- bis 13.09.2026 lag er in
     einem ::before mit inset:0. Das war nur so hoch wie der Bildschirm und
     scrollte mit dem Inhalt weg: Ist das Menue laenger als das Handy hoch,
     endete der Verlauf mitten im Menue mit einer harten Kante. Ein
     Hintergrund bleibt in einem scrollenden Element dagegen stehen. */
  background:
    radial-gradient(40rem 30rem at 90% 0%, var(--glow-pink), transparent 60%),
    radial-gradient(30rem 24rem at 0% 100%, var(--glow-season), transparent 60%),
    var(--color-bg);
  opacity: 0;
  transition: opacity .28s var(--ease);
  overflow-y: auto;
}
.mobile-menu.is-open { opacity: 1; }

.mobile-menu-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 4.5rem;
}
/* Die dunkle Pille nur dann, wenn zum Logo KEINE helle Variante existiert --
   sonst stand im hellen Schema das Logo mit dunklen Buchstaben auf dunklem
   Grund und sah voellig anders aus als im Kopfbereich. */
.mobile-menu-top .brand-box:not(.has-light) { background: var(--ink-dark); }

.mobile-menu-list {
  list-style: none;
  margin: auto 0;
  padding: 1rem 0 1.5rem;
  counter-reset: menu;
}
.mobile-menu-list a {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem 0;
  border-top: 1px solid var(--line-soft);
  color: var(--color-text);
  font-size: clamp(1.7rem, 7.5vw, 2.5rem);
  font-weight: 600;
  letter-spacing: -.035em;
  line-height: 1.1;
  text-decoration: none;
  opacity: 0;
  transform: translateY(16px);
  transition: transform .5s var(--ease), opacity .5s var(--ease), color .2s;
}
.mobile-menu-list li:last-child a { border-bottom: 1px solid var(--line-soft); }
.mobile-menu-list a::before {
  counter-increment: menu;
  content: counter(menu, decimal-leading-zero);
  color: var(--accent-ink);
  font-family: var(--mono);
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: .14em;
}
.mobile-menu-list a .chev { margin-left: auto; color: var(--dim); }
.mobile-menu-list a[aria-current="page"] { color: var(--accent-ink); }
.mobile-menu.is-open .mobile-menu-list a { opacity: 1; transform: none; }
.mobile-menu.is-open .mobile-menu-list li:nth-child(1) a { transition-delay: .05s; }
.mobile-menu.is-open .mobile-menu-list li:nth-child(2) a { transition-delay: .11s; }
.mobile-menu.is-open .mobile-menu-list li:nth-child(3) a { transition-delay: .17s; }
.mobile-menu.is-open .mobile-menu-list li:nth-child(4) a { transition-delay: .23s; }

.mobile-menu-foot {
  display: grid;
  gap: .8rem;
  opacity: 0;
  transform: translateY(12px);
  transition: transform .5s var(--ease) .3s, opacity .5s var(--ease) .3s;
}
.mobile-menu.is-open .mobile-menu-foot { opacity: 1; transform: none; }
.mobile-menu-foot .btn { min-height: 3.4rem; font-size: 1.05rem; }
.mobile-menu-contact { display: flex; flex-wrap: wrap; gap: .5rem; }
.mobile-menu-contact a,
.mobile-menu-contact button {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  min-height: 2.8rem;
  padding: .4rem 1rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--color-text-muted);
  font-family: inherit;
  font-size: .88rem;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
}
.mobile-menu-contact svg { width: 1rem; height: 1rem; color: var(--accent-ink); }

/* ---------- Aktionsleiste unten (nur schmal) ---------- */

.action-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  display: flex;
  gap: .6rem;
  padding: .65rem var(--gutter) calc(.65rem + env(safe-area-inset-bottom));
  background: var(--header-bg);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  backdrop-filter: blur(16px) saturate(1.4);
  border-top: 1px solid var(--line);
  animation: bar-in .6s var(--ease) .4s both;
}
@keyframes bar-in {
  from { transform: translateY(110%); }
  to { transform: none; }
}
.action-bar .btn { flex: 1 1 auto; min-height: 3.1rem; }
.action-bar .action-bar-phone {
  flex: none;
  width: 3.1rem;
  min-height: 3.1rem;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--panel);
  color: var(--color-text);
  box-shadow: none;
}
/* Platzhalter im Fluss, damit die feste Leiste den Fuss nicht verdeckt */
.action-bar-spacer { height: calc(4.6rem + env(safe-area-inset-bottom)); }

/* Solange die Knoepfe im Hero zu sehen sind, wartet die Leiste unten.
   Vorher stand "Termin anfragen" auf dem Handy im ersten Bild zweimal
   uebereinander. Die Klasse .js-leiste setzt site.js nur auf Seiten mit
   Hero-Knoepfen; ueberall sonst (und ohne JavaScript) bleibt es bei der
   Einblend-Animation oben. Die Animation muss dort AUS sein: mit
   "fill-mode: both" haelt sie transform fest, und das Verstecken
   ueber transform griffe nie. */
.js-leiste .action-bar {
  animation: none;
  transition: transform .45s var(--ease);
}
.js-leiste.action-bar-versteckt .action-bar { transform: translateY(110%); }
@media (prefers-reduced-motion: reduce) {
  .js-leiste .action-bar { transition: none; }
}

/* ---------- Seitenkopf / Hero ---------- */

.hero {
  position: relative;
  padding: clamp(2.5rem, 7vw, 5.5rem) 0 clamp(2rem, 5vw, 3.5rem);
}
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(2.25rem, 5vw, 4rem);
  align-items: center;
}

.status {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  margin-bottom: 1.6rem;
  padding: .42rem .95rem .42rem .7rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--color-text-muted);
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .06em;
}
.status .dot {
  position: relative;
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: var(--accent-ink);
}
.status .dot::after {
  content: "";
  position: absolute;
  inset: -.3rem;
  border-radius: 50%;
  border: 1px solid var(--accent-ink);
  opacity: .5;
  animation: pulse 2.6s ease-out infinite;
}
@keyframes pulse {
  0%   { transform: scale(.55); opacity: .7; }
  70%  { transform: scale(1.6); opacity: 0; }
  100% { transform: scale(1.6); opacity: 0; }
}

.hero h1 {
  max-width: 14ch;
  margin: 0 0 1.25rem;
  font-size: clamp(2.8rem, 7.4vw, 5.4rem);
  font-weight: 600;
  letter-spacing: -.045em;
  line-height: 1;
}
.hero h1 .line {
  display: block;
  padding: .04em 0 .16em;
  margin-bottom: -.12em;
  overflow: hidden;
}
.hero h1 .line > span {
  display: inline-block;
  animation: rise .9s var(--ease) both;
}
.hero h1 .line:nth-child(2) > span { animation-delay: .12s; }
.hero h1 .accent-word { font-size: 1.04em; padding-right: .06em; }
@keyframes rise {
  from { transform: translateY(105%); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

.hero-in { animation: fade-up .8s var(--ease) both; animation-delay: var(--d, 0s); }
@keyframes fade-up {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

.hero .lead { margin-bottom: 1.4rem; }

/* Wechselndes Wort ("Heute Lust auf ...?") */
.rotor-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .3em;
  margin: 0 0 1.8rem;
  color: var(--color-text-muted);
  font-size: 1.05rem;
}
.rotor {
  display: inline-grid;
  color: var(--accent-ink);
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.3em;
  line-height: 1.15;
}
.rotor > span {
  grid-area: 1 / 1;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(.4em);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.rotor > span.is-active { opacity: 1; transform: none; }
.rotor > span.is-leaving { opacity: 0; transform: translateY(-.4em); }

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

/* Marken-Kachel: bleibt in beiden Schemata dunkel, damit die weissen
   Buchstaben des Logos sichtbar bleiben */
.hero-visual {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 5 / 4;
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: calc(var(--radius-lg) + 8px);
  background:
    radial-gradient(60% 55% at 72% 18%, rgba(230, 25, 122, .34), transparent 70%),
    radial-gradient(50% 50% at 12% 92%, rgba(var(--season-rgb), .3), transparent 70%),
    linear-gradient(160deg, #261c31, #110d17 72%);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  isolation: isolate;
  animation: fade-up 1s var(--ease) .25s both;
}
.hero-visual::before,
.hero-visual::after {
  content: "";
  position: absolute;
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 50%;
  pointer-events: none;
  animation: breathe 9s ease-in-out infinite;
}
.hero-visual::before { right: -22%; bottom: -40%; width: 78%; aspect-ratio: 1; }
.hero-visual::after { left: -18%; top: -30%; width: 52%; aspect-ratio: 1; animation-delay: -4s; }
@keyframes breathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.06); }
}
.hero-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: .62;
  transform: scale(1.06);
  animation: kenburns 26s ease-in-out infinite alternate;
  pointer-events: none;
}
.hero-shade {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(60% 55% at 72% 18%, rgba(230, 25, 122, .28), transparent 70%),
    linear-gradient(180deg, rgba(17, 13, 23, .35), rgba(17, 13, 23, .82) 88%);
  pointer-events: none;
}
@keyframes kenburns {
  from { transform: scale(1.06) translate(0, 0); }
  to { transform: scale(1.14) translate(-2%, -2%); }
}
.hero-glow {
  position: absolute;
  left: 50%;
  top: 58%;
  width: 60%;
  height: 30%;
  border-radius: 50%;
  background: rgba(230, 25, 122, .45);
  filter: blur(40px);
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.hero-logo {
  position: relative;
  z-index: 1;
  width: min(72%, 30rem);
  height: auto;
  filter: drop-shadow(0 26px 40px rgba(0, 0, 0, .55));
  animation: float 7s ease-in-out infinite;
}
@keyframes float {
  0%, 100% { transform: translateY(0) rotate(-1.2deg); }
  50% { transform: translateY(-10px) rotate(1.2deg); }
}
.sparkle {
  position: absolute;
  width: 1.4rem;
  height: 1.4rem;
  color: #fff;
  animation: twinkle 3.4s ease-in-out infinite;
  pointer-events: none;
}
.sparkle-1 { top: 14%; left: 13%; }
.sparkle-2 { top: 68%; right: 13%; width: 1.1rem; height: 1.1rem; color: #ff5aa5; animation-delay: 1.1s; }
.sparkle-3 { top: 24%; right: 21%; width: .8rem; height: .8rem; animation-delay: 2.1s; }
.sparkle-4 { bottom: 16%; left: 22%; width: .9rem; height: .9rem; color: #ff5aa5; animation-delay: .6s; }
@keyframes twinkle {
  0%, 100% { transform: scale(.5) rotate(0deg); opacity: .25; }
  50% { transform: scale(1) rotate(25deg); opacity: 1; }
}
.hero-visual-tag {
  position: absolute;
  left: 1.1rem;
  bottom: 1.1rem;
  z-index: 1;
  padding: .35rem .7rem;
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 999px;
  background: rgba(20, 17, 26, .55);
  color: #d8cfe0;
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* Fakten-Leiste */
.facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  margin: clamp(2.5rem, 6vw, 4rem) 0 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--line);
  overflow: hidden;
}
.facts > div { padding: 1.25rem 1.3rem; background: var(--color-bg); }
.facts dt {
  display: flex;
  align-items: center;
  gap: .5rem;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.facts dt svg { width: .95rem; height: .95rem; color: var(--accent-ink); }
.facts dd {
  margin: .5rem 0 0;
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: -.015em;
  line-height: 1.35;
}

/* Kopf einer Unterseite */
.page-head { padding: clamp(2.5rem, 7vw, 5rem) 0 clamp(1.5rem, 4vw, 2.5rem); }
.page-head h1 {
  max-width: 18ch;
  margin: 0 0 1.2rem;
  font-size: clamp(2.4rem, 6vw, 4.2rem);
  font-weight: 600;
  letter-spacing: -.045em;
  line-height: 1.02;
}
.page-head .lead { margin: 0; }

/* ---------- Abschnitte ---------- */

.section { padding: clamp(3.25rem, 8vw, 6.5rem) 0; }
.section + .section { border-top: 1px solid var(--line-soft); }
.section-tight { padding-top: clamp(1.5rem, 4vw, 2.5rem); }

.section-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  margin-bottom: clamp(2rem, 5vw, 3.25rem);
}
.section-head h2 {
  max-width: 20ch;
  margin: 0;
  font-size: clamp(2rem, 4.4vw, 3.3rem);
  font-weight: 600;
  letter-spacing: -.04em;
  line-height: 1.04;
}
.section-head .lead { margin: 0; }
.section-more { display: flex; flex-wrap: wrap; justify-content: center; gap: .75rem; margin: 1.75rem 0 0; }
.about-more { margin-top: 1.6rem; }

/* ---------- Karten ---------- */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 255px), 1fr));
  gap: 1rem;
}
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 1.8rem 1.6rem 1.7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel);
  overflow: hidden;
  transition: transform .35s var(--ease), border-color .35s, box-shadow .35s;
}
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(22rem 12rem at 85% -10%, var(--accent-soft), transparent 70%);
  opacity: 0;
  transition: opacity .35s;
  pointer-events: none;
}
.card:hover { transform: translateY(-5px); border-color: var(--accent-line); box-shadow: var(--shadow-lg); }
.card:hover::after { opacity: 1; }

.card-icon {
  display: grid;
  place-items: center;
  width: 2.8rem;
  height: 2.8rem;
  margin-bottom: 1.4rem;
  border: 1px solid var(--accent-line);
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent-ink);
  transition: transform .35s var(--ease);
}
.card:hover .card-icon { transform: rotate(-7deg) scale(1.06); }
.card-icon svg { width: 1.3rem; height: 1.3rem; }
.card h3 { margin: 0 0 .5rem; font-size: 1.2rem; font-weight: 600; letter-spacing: -.02em; }
.card p { color: var(--color-text-muted); font-size: .96rem; }
.card-index {
  position: absolute;
  top: 1.5rem;
  right: 1.5rem;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .12em;
}

/* Ablauf in drei Schritten */
.steps {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
}
.step {
  position: relative;
  padding: 1.5rem 1.4rem 1.5rem 4.1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel);
}
.step::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 1.4rem;
  top: 1.55rem;
  color: var(--accent-ink);
  font-family: var(--mono);
  font-size: .78rem;
  letter-spacing: .14em;
}
.step h3 { margin: 0 0 .35rem; font-size: 1.05rem; font-weight: 600; letter-spacing: -.015em; }
.step p { margin: 0; color: var(--color-text-muted); font-size: .93rem; }

/* ---- Preisliste (/leistungen) ----------------------------------------
   Zwei Spalten am Rechner: links was, rechts was es kostet. Am Handy
   untereinander -- eine echte Tabelle waere dort nicht lesbar, deshalb
   bewusst eine Liste und kein <table>. Die Trennlinie zwischen den Zeilen
   ersetzt die Tabellenoptik, ohne sie zu erzwingen. */
.preis-gruppe { margin-top: 2.2rem; }
.preis-gruppe:first-of-type { margin-top: 1.4rem; }

.preis-gruppe-titel {
  margin: 0 0 .2rem;
  font-size: 1.12rem;
  font-weight: 600;
  letter-spacing: -.015em;
}

.preis-liste { margin: 0; padding: 0; list-style: none; }

.preis-zeile {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .3rem 1.2rem;
  padding: .95rem 0;
  border-bottom: 1px solid var(--line-soft);
}
.preis-zeile:last-child { border-bottom: 0; }

.preis-was { flex: 1 1 16rem; min-width: 0; }
.preis-name { display: block; font-weight: 500; }
.preis-text {
  display: block;
  margin-top: .2rem;
  color: var(--color-text-muted);
  font-size: .88rem;
  line-height: 1.5;
}

.preis-zahlen {
  display: flex;
  align-items: baseline;
  gap: .75rem;
  flex: 0 0 auto;
  white-space: nowrap;
}
.preis-betrag { font-weight: 600; font-variant-numeric: tabular-nums; }
.preis-dauer {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  color: var(--dim);
  font-size: .82rem;
}
.preis-dauer .icon { width: .95rem; height: .95rem; }

.preis-fuss {
  margin: 2rem 0 0;
  color: var(--color-text-muted);
  font-size: .88rem;
  line-height: 1.6;
}

/* Am Handy rutscht der Preis unter den Namen und links an den Rand --
   nebeneinander wird es bei langen Namen sonst zweizeilig und unruhig. */
@media (max-width: 34rem) {
  .preis-zeile { flex-direction: column; align-items: flex-start; gap: .35rem; }
  .preis-zahlen { white-space: normal; }
  /* WICHTIG: In der Spaltenrichtung bezieht sich flex-basis auf die HOEHE.
     Ohne diese Zeile wuerde aus dem "16rem" der Grundregel eine Mindesthoehe
     von 256 px je Zeile -- gemessen war jede Zeile dreimal so hoch wie noetig,
     und zwar nur am Handy. */
  .preis-was { flex: 0 0 auto; }
}

/* ---------- Galerie / Arbeiten ---------- */

.work-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .85rem;
}
.work-card {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel);
  overflow: hidden;
  transition: transform .4s var(--ease), border-color .35s, box-shadow .4s;
}
.work-card:hover { transform: translateY(-6px); border-color: var(--accent-line); box-shadow: var(--shadow-lg); }
a.work-card { color: inherit; text-decoration: none; }

/* height:auto ist Pflicht: sonst gewinnt das HTML-height-Attribut und das
   Bild wird verzerrt (ist schon einmal passiert). */
.work-img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  transition: transform .7s var(--ease);
}
.work-card:hover .work-img { transform: scale(1.05); }
/* Galeriebilder stecken seit 14.09.2026 in <picture> (Varianten fuers Handy).
   display: contents laesst das Layout unberuehrt: das <img> verhaelt sich,
   als staende es allein da. */
.bild-rahmen { display: contents; }

/* Wunschdesign aus der Galerie oben im Anfrageformular (14.09.2026). */
.wunschdesign {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin: 0 0 1.25rem;
  padding: .75rem .9rem;
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-lg);
  background: var(--panel);
}
.wunschdesign-bild {
  flex: none;
  width: 4.5rem;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 10px;
}
.wunschdesign-label { margin: 0; font-size: .72rem; letter-spacing: .06em; text-transform: uppercase; color: var(--color-text-muted); }
.wunschdesign-titel { margin: .15rem 0 .3rem; font-weight: 600; }
.wunschdesign-weg { font-size: .8rem; color: var(--color-text-muted); }
.work-anfrage { margin: .15rem 0 .55rem; font-size: .85rem; }
.work-placeholder {
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 5;
  background: var(--color-surface);
  color: var(--dim);
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.work-body { display: grid; gap: .35rem; padding: .9rem 1rem 1.1rem; }
.work-meta-row { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.work-date {
  color: var(--dim);
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .08em;
}
.work-tag {
  width: fit-content;
  padding: .26rem .6rem;
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.work-body h3 { margin: 0; font-size: 1rem; font-weight: 600; letter-spacing: -.015em; }
.work-body p {
  display: -webkit-box;
  margin: 0;
  color: var(--color-text-muted);
  font-size: .86rem;
  line-height: 1.55;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Filter-Chips (nur mit JS sinnvoll) */
.filters { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0 0 1.5rem; }
html:not(.js) .filters { display: none; }
.filter {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: 2.75rem;
  padding: .3rem 1rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--color-text-muted);
  font-family: inherit;
  font-size: .86rem;
  font-weight: 500;
  cursor: pointer;
  transition: border-color .2s, background-color .2s, color .2s, transform .25s var(--ease);
}
.filter:hover { border-color: var(--line-strong); color: var(--color-text); transform: translateY(-1px); }
.filter[aria-pressed="true"] { border-color: var(--color-accent); background: var(--accent-soft); color: var(--color-text); }
.filter .count { color: var(--dim); font-family: var(--mono); font-size: .68rem; }

.empty {
  padding: clamp(2.5rem, 6vw, 4rem) 1.5rem;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--panel);
  text-align: center;
}
.empty .card-icon { margin: 0 auto 1.2rem; }
.empty h3 { margin: 0 0 .5rem; font-size: 1.3rem; letter-spacing: -.02em; }
.empty p { max-width: 44ch; margin: 0 auto; color: var(--color-text-muted); }
.empty .section-more { max-width: none; margin: 1.5rem auto 0; }

/* Lightbox (native <dialog>, per JS erzeugt) */
.lightbox {
  max-width: min(96vw, 1100px);
  max-height: 96vh;
  padding: 0;
  border: 0;
  background: transparent;
  color: #f7f2f8;
  overflow: visible;
}
.lightbox::backdrop {
  background: rgba(10, 8, 14, .88);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.lightbox[open] { animation: fade-up .3s var(--ease); }
.lightbox-figure { display: grid; gap: .8rem; justify-items: center; margin: 0; }
.lightbox-img {
  width: auto;
  height: auto;
  max-width: min(96vw, 1100px);
  max-height: 80vh;
  border-radius: var(--radius-lg);
  background: #000;
  box-shadow: var(--shadow-lg);
}
.lightbox-caption { max-width: 60ch; text-align: center; font-size: .9rem; line-height: 1.5; }
.lightbox-caption b { display: block; font-size: 1rem; }
.lightbox-caption span { color: #b9aec6; }
.lightbox-btn {
  position: fixed;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 2.8rem;
  height: 2.8rem;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 50%;
  background: rgba(20, 17, 26, .7);
  color: #fff;
  cursor: pointer;
  transition: background-color .2s, transform .2s var(--ease);
}
.lightbox-btn:hover { background: var(--color-accent); transform: scale(1.06); }
.lightbox-btn svg { width: 1.15rem; height: 1.15rem; }
.lightbox-close { top: 1rem; right: 1rem; }
.lightbox-prev { left: .75rem; top: 50%; transform: translateY(-50%); }
.lightbox-next { right: .75rem; top: 50%; transform: translateY(-50%); }
.lightbox-prev:hover, .lightbox-next:hover { transform: translateY(-50%) scale(1.06); }

/* ---------- Ueber mich ---------- */

.about-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(2.25rem, 5vw, 4rem);
  align-items: center;
}
.portrait {
  position: relative;
  width: 100%;
  max-width: 22rem;
  margin: 0 auto;
  padding: .6rem 1rem 1.2rem .6rem;
}
.portrait::before {
  content: "";
  position: absolute;
  inset: 1.4rem -.4rem -.2rem 1.6rem;
  border: 1px solid var(--accent-line);
  border-radius: calc(var(--radius-lg) + 8px);
  transform: rotate(3deg);
  transition: transform .5s var(--ease);
}
.portrait:hover::before { transform: rotate(5deg) translate(4px, 4px); }
.portrait-frame {
  position: relative;
  border: 1px solid var(--line);
  border-radius: calc(var(--radius-lg) + 8px);
  background: var(--color-surface);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  transform: rotate(-2deg);
  transition: transform .5s var(--ease);
}
.portrait:hover .portrait-frame { transform: rotate(0deg) scale(1.02); }
.portrait-frame img { width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; }
.portrait-badge {
  position: absolute;
  left: -.4rem;
  bottom: .2rem;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .6rem .95rem;
  border-radius: 999px;
  background: var(--ink-dark);
  color: #fff;
  box-shadow: var(--shadow-md);
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  transform: rotate(-4deg);
}
.portrait-badge svg { width: .95rem; height: .95rem; color: #ff5aa5; }

.about-copy h2 {
  max-width: 18ch;
  margin-bottom: 1.3rem;
  font-size: clamp(1.9rem, 3.8vw, 2.9rem);
  font-weight: 600;
  letter-spacing: -.04em;
  line-height: 1.06;
}
.about-copy p { color: var(--color-text-muted); font-size: 1.02rem; line-height: 1.75; }
.about-copy p.is-first { color: var(--color-text); font-size: 1.12rem; }

.tags { display: flex; flex-wrap: wrap; gap: .5rem; margin: 1.8rem 0 0; padding: 0; list-style: none; }
.tags li {
  padding: .42rem .85rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--color-text-muted);
  font-size: .82rem;
  transition: border-color .2s, color .2s, transform .25s var(--ease);
}
.tags li:hover { border-color: var(--accent-line); color: var(--color-text); transform: translateY(-2px); }

/* Seit dem 12.09.2026 stehen in dieser Liste auch Verweise (weitere Arbeiten
   am Ende einer Galerie-Detailseite). Die Kachel selbst bringt Rahmen und
   Abstand schon mit -- der Verweis darin soll nur die Farbe erben und die
   ganze Kachel anklickbar machen, statt nur die Buchstaben. */
.tags li:has(a) { padding: 0; }
.tags li a {
  display: block;
  padding: .42rem .85rem;
  color: inherit;
  text-decoration: none;
}

/* ---------- Aufruf ---------- */

.cta {
  position: relative;
  display: grid;
  gap: 1.5rem;
  padding: clamp(2rem, 5vw, 3.5rem);
  border: 1px solid var(--accent-line);
  border-radius: calc(var(--radius-lg) + 8px);
  background: radial-gradient(40rem 20rem at 90% -30%, var(--accent-soft), transparent 70%), var(--panel);
  overflow: hidden;
}
.cta::before {
  content: "";
  position: absolute;
  right: -12%;
  bottom: -70%;
  width: 40%;
  aspect-ratio: 1;
  border: 1px solid var(--accent-line);
  border-radius: 50%;
  pointer-events: none;
}
.cta > * { position: relative; }
.cta h2 {
  max-width: 18ch;
  margin: 0 0 .7rem;
  font-size: clamp(1.85rem, 4vw, 2.9rem);
  font-weight: 600;
  letter-spacing: -.04em;
  line-height: 1.06;
}
.cta p { max-width: 46ch; margin: 0; color: var(--color-text-muted); }
.cta-actions { display: flex; flex-wrap: wrap; gap: .75rem; }
.cta .btn { min-height: 3.3rem; padding-inline: 1.7rem; font-size: 1rem; }

/* ---------- Kontakt / Terminanfrage ---------- */

.contact-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2.5rem;
  align-items: start;
}
.contact-aside .lead { margin-bottom: 0; }
.contact-points { display: grid; gap: .6rem; margin: 1.6rem 0 0; padding: 0; list-style: none; }
.contact-points a,
.contact-points .point {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding: .85rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
  color: inherit;
  text-decoration: none;
  transition: border-color .25s, transform .25s var(--ease), background-color .25s;
}
.contact-points a:hover { border-color: var(--accent-line); background: var(--accent-soft); transform: translateX(4px); }
.contact-points .card-icon { width: 2.4rem; height: 2.4rem; margin: 0; }
.contact-points small {
  display: block;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.contact-points span { display: block; font-weight: 600; letter-spacing: -.01em; }

/* ---------- Umkreiskarte (Kontaktseite) ----------
   Grundkarte als Bild, darueber eine SVG-Ebene mit Kreis und Punkten. Beide
   haben dieselbe viewBox -- deshalb liegt der Kreis genau auf dem Ort. Die
   Flaeche bleibt in beiden Farbschemata dunkel, wie der Fuss der Seite. */
.umkreis-block { margin-top: 2rem; }
.karte-umkreis { margin: .8rem 0 0; }
.karte-flaeche {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg, 18px);
  background: var(--ink-dark);
}
/* Eine SVG mit zugeschnittener viewBox: Grundkarte als <image>, Gebiet und
   Punkte darueber -- dadurch passt der Ausschnitt sich dem km-Wert an. */
.karte-bild { display: block; width: 100%; height: auto; aspect-ratio: 1; }
.karte-grenze {
  fill: none;
  stroke: var(--color-accent);
  stroke-linecap: round;
  stroke-linejoin: round;
}
.karte-aussen { fill: #0d0a12; opacity: .6; }
.karte-kreis {
  fill: rgba(226, 25, 122, .06);
  stroke: var(--color-accent);
  stroke-width: 4;
  stroke-dasharray: 14 10;
}
.karte-mitte { fill: var(--color-accent); stroke: #fff; stroke-width: 5; }
.karte-mitte-text,
.karte-besucher text {
  fill: #fff;
  font: 700 30px var(--font-body, system-ui, sans-serif);
  paint-order: stroke;
  stroke: var(--ink-dark);
  stroke-width: 8px;
}
.karte-besucher circle { fill: #fff; stroke: var(--color-accent); stroke-width: 7; }
.karte-umkreis figcaption { margin-top: .45rem; color: var(--dim); font-size: .72rem; }
.karte-umkreis figcaption a { color: inherit; }
.umkreis-orte { margin: .8rem 0 0; color: var(--color-text-muted); font-size: .92rem; line-height: 1.55; }

/* ---------- /mobil: Einsatzgebiet und Orte nach Entfernung ---------- */
.mobil-gebiet { display: grid; gap: 1.6rem; align-items: center; }
.orte-baender { display: grid; gap: 1rem; }
.orte-band {
  padding: 1.2rem 1.3rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg, 18px);
  background: var(--panel);
}
.orte-band h3 { margin: 0 0 .5rem; font-size: 1.05rem; }
.orte-staedte { margin: 0; font-weight: 600; line-height: 1.6; }
.orte-alle { margin-top: .7rem; }
.orte-alle summary { cursor: pointer; color: var(--accent-ink); font-size: .9rem; }
.orte-alle p { margin: .6rem 0 0; color: var(--color-text-muted); font-size: .88rem; line-height: 1.65; }
.orte-quelle { margin-top: 1rem; color: var(--dim); font-size: .75rem; }
.orte-quelle a { color: inherit; }

@media (min-width: 860px) {
  .mobil-gebiet { grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); gap: 3rem; }
  .orte-baender { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start; }
}

.form-card {
  padding: clamp(1.25rem, 3.5vw, 2.25rem);
  border: 1px solid var(--line);
  border-radius: calc(var(--radius-lg) + 6px);
  background: var(--panel-solid);
  box-shadow: var(--shadow-lg);
}
/* Falle fuer Formular-Roboter: fuer Menschen unsichtbar, kein display:none */
.hp-field {
  position: absolute;
  left: -5000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.1rem; }
.field { display: grid; gap: .45rem; align-content: start; }
fieldset.field { min-width: 0; margin: 0; padding: 0; border: 0; }
.field > label:not(.check),
.field-legend {
  margin: 0;
  padding: 0;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .68rem;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.field-legend { display: block; }
.field input:not([type="radio"]):not([type="checkbox"]),
.field textarea {
  width: 100%;
  min-height: 3.1rem;
  padding: .8rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--field-bg);
  color: var(--color-text);
  font-family: inherit;
  font-size: 1rem;
  line-height: 1.4;
  transition: border-color .2s, box-shadow .2s, background-color .2s;
}
.field textarea { min-height: 8rem; resize: vertical; }
.field input:not([type="radio"]):not([type="checkbox"]):hover,
.field textarea:hover { border-color: var(--line-strong); }
.field input:not([type="radio"]):not([type="checkbox"]):focus,
.field textarea:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.field input::placeholder,
.field textarea::placeholder { color: var(--dim); opacity: 1; }
.field-hint { margin: .1rem 0 0; color: var(--dim); font-size: .8rem; line-height: 1.5; }
.field-hint:empty { display: none; }

/* Umschalter Studio / mobil */
.choices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .6rem; }
.choice { position: relative; cursor: pointer; }
.choice input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
.choice-body {
  display: flex;
  align-items: center;
  gap: .75rem;
  min-height: 3.6rem;
  padding: .7rem .9rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--field-bg);
  transition: border-color .2s, background-color .2s, box-shadow .2s, transform .2s var(--ease);
}
.choice:hover .choice-body { border-color: var(--line-strong); }
.choice-body svg { width: 1.2rem; height: 1.2rem; flex: none; color: var(--dim); transition: color .2s; }
.choice-body b { display: block; font-size: .95rem; font-weight: 600; line-height: 1.25; }
.choice-body small { display: block; color: var(--dim); font-size: .74rem; line-height: 1.3; }
.choice input:checked + .choice-body {
  border-color: var(--color-accent);
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--color-accent);
}
.choice input:checked + .choice-body svg { color: var(--accent-ink); }
.choice input:focus-visible + .choice-body { outline: 2px solid var(--fokus-ring); outline-offset: 3px; }

/* Kompakte Variante fuer die Leistungs-Kategorien im Terminformular:
   mehrere kleine Felder statt zweier grosser. Automatische Spaltenzahl statt
   fester zwei -- bei fuenf Kategorien saehe eine 2er-Reihe mit einem
   einsamen Rest unten unruhig aus. */
.choices-kompakt {
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: .5rem;
}
.choices-kompakt .choice-body {
  min-height: 2.9rem;
  padding: .55rem .8rem;
}
.choices-kompakt .choice-body b { font-size: .9rem; font-weight: 500; }

.field-legend-zusatz {
  display: block;
  margin-top: .15rem;
  color: var(--dim);
  font-size: .78rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}

/* Zeiten-Kasten im Terminformular: kurz und ruhig, er soll die Aufmerksamkeit
   nicht vom Formular wegziehen. */
.zeiten-kasten {
  padding: .9rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
}
.zeiten-liste { display: grid; gap: .3rem; margin: .5rem 0 0; padding: 0; list-style: none; }
.zeiten-liste li { display: flex; gap: .6rem; font-size: .92rem; }
.zeiten-liste b { min-width: 6.5rem; font-weight: 600; }
.zeiten-liste span { color: var(--color-text-muted); }
.zeiten-kasten .field-hint { margin-top: .6rem; }

/* ---- Datei-Auswahl im Seitendesign -----------------------------------
   Der native Knopf heisst auf jedem System anders ("Durchsuchen...",
   "Datei auswaehlen", "Choose File") und sieht ueberall fremd aus. Deshalb
   traegt das <label> das Aussehen und das echte Feld wird unsichtbar
   gemacht.

   Bewusst NICHT display:none und nicht visibility:hidden: beides nimmt das
   Feld aus der Tastatur-Reihenfolge. So bleibt es fokussierbar, und der
   Fokusrahmen wandert per :focus-visible auf das Label. */
.datei-feld { display: grid; gap: .7rem; }

.datei-eingabe {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
}

.datei-knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .55rem;
  justify-self: start;
  min-height: 3rem;
  padding: .55rem 1.3rem;
  border: 1px dashed var(--line-strong);
  border-radius: 999px;
  background: var(--panel);
  color: var(--color-text);
  font-size: .95rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color .2s, background-color .2s, transform .22s var(--ease);
}
.datei-knopf svg { width: 1.1rem; height: 1.1rem; color: var(--accent-ink); }
.datei-knopf:hover { border-color: var(--color-accent); background: var(--accent-soft); transform: translateY(-1px); }
.datei-knopf:active { transform: translateY(0); }
.datei-eingabe:focus-visible + .datei-knopf { outline: 2px solid var(--fokus-ring); outline-offset: 3px; }

/* Ausgewaehltes Bild: kleine Vorschau, damit vor dem Absenden klar ist,
   welches Foto mitgeht -- am Handy greift man sich schnell das falsche. */
.datei-gewaehlt {
  display: flex;
  align-items: center;
  gap: .85rem;
  padding: .6rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--field-bg);
}
.datei-gewaehlt img {
  width: 3.4rem;
  height: 3.4rem;
  flex: none;
  border-radius: 10px;
  object-fit: cover;
}
.datei-gewaehlt-text { display: grid; gap: .2rem; min-width: 0; }
.datei-gewaehlt-text span {
  overflow: hidden;
  font-size: .88rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.datei-weg {
  justify-self: start;
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent-ink);
  font: inherit;
  font-size: .82rem;
  text-decoration: underline;
  cursor: pointer;
}

.address-input-row { display: grid; grid-template-columns: minmax(0, 1fr); gap: .5rem; }
.btn-locate {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: 3.1rem;
  padding: 0 1rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: transparent;
  color: var(--color-text);
  font-family: inherit;
  font-size: .9rem;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: border-color .2s, background-color .2s;
}
.btn-locate:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.btn-locate:disabled { opacity: .6; cursor: progress; }
.btn-locate svg { width: 1rem; height: 1rem; color: var(--accent-ink); }

.check {
  display: flex;
  align-items: flex-start;
  gap: .8rem;
  padding: .9rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--field-bg);
  color: var(--color-text-muted);
  font-size: .9rem;
  line-height: 1.55;
  cursor: pointer;
  transition: border-color .2s;
}
.check:hover { border-color: var(--line-strong); }
.check input { flex: none; width: 1.25rem; height: 1.25rem; margin: .15rem 0 0; accent-color: var(--color-accent); }
.check a { color: var(--color-text); text-underline-offset: .2em; }

.form-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem; margin-top: 1.5rem; }
.form-actions .btn { min-height: 3.3rem; padding-inline: 1.8rem; font-size: 1rem; }
.form-note { margin: 0; color: var(--dim); font-size: .8rem; line-height: 1.5; }

.notice {
  display: flex;
  gap: .9rem;
  margin: 0 0 1.25rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--color-danger);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--panel);
}
.notice svg { width: 1.2rem; height: 1.2rem; flex: none; margin-top: .15rem; color: var(--color-danger); }
.notice ul { margin: 0; padding-left: 1.1rem; }
.notice li { margin: .2rem 0; }
.notice p { margin: 0 0 .3rem; font-weight: 600; }

.success {
  position: relative;
  display: grid;
  gap: .4rem;
  justify-items: center;
  margin: 0 0 1.5rem;
  padding: clamp(1.75rem, 5vw, 2.75rem) 1.5rem;
  border: 1px solid var(--accent-line);
  border-radius: calc(var(--radius-lg) + 6px);
  background: radial-gradient(30rem 16rem at 50% -20%, var(--accent-soft), transparent 70%), var(--panel);
  text-align: center;
  overflow: hidden;
  animation: fade-up .6s var(--ease) both;
}
.success .sparkle { color: var(--accent-ink); }
.success-badge {
  display: grid;
  place-items: center;
  width: 4.2rem;
  height: 4.2rem;
  border-radius: 50%;
  background: var(--color-accent);
  color: #fff;
  box-shadow: var(--shadow-accent);
  animation: pop .7s var(--ease) .15s both;
}
.success-badge svg { width: 1.9rem; height: 1.9rem; }
.success-badge path {
  stroke-dasharray: 32;
  stroke-dashoffset: 32;
  animation: draw .5s ease .55s forwards;
}
@keyframes pop {
  0% { transform: scale(.3); opacity: 0; }
  65% { transform: scale(1.12); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
@keyframes draw { to { stroke-dashoffset: 0; } }
.success h2 { margin: .7rem 0 0; font-size: clamp(1.5rem, 3vw, 1.9rem); letter-spacing: -.03em; }
.success p { max-width: 42ch; margin: 0; color: var(--color-text-muted); }

/* ---------- Bewertungen ---------- */

.stars { display: inline-flex; gap: .12rem; line-height: 0; }
.stars .star { width: 1.05rem; height: 1.05rem; color: var(--star-off); fill: var(--star-off); stroke: none; }
.stars .star.is-on { color: var(--star); fill: var(--star); }

.rating-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-bottom: clamp(1.5rem, 4vw, 2.5rem);
  padding: 1.25rem 1.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel);
}
.rating-summary-score { display: flex; align-items: center; gap: 1rem; }
.rating-summary-number {
  font-family: var(--serif);
  font-size: clamp(2.6rem, 6vw, 3.4rem);
  font-weight: 600;
  letter-spacing: -.04em;
  line-height: 1;
}
.rating-summary-score .stars .star { width: 1.3rem; height: 1.3rem; }
.rating-summary-score small {
  display: block;
  margin-top: .35rem;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.review-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
}
.review-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .9rem;
  padding: 1.7rem 1.5rem 1.4rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel);
  overflow: hidden;
  transition: transform .35s var(--ease), border-color .35s, box-shadow .35s;
}
.review-card::before {
  content: "\201E";
  position: absolute;
  top: -.35rem;
  right: 1.1rem;
  color: var(--accent-ink);
  font-family: var(--serif);
  font-size: 5rem;
  line-height: 1;
  opacity: .28;
  pointer-events: none;
}
.review-card:hover { transform: translateY(-5px); border-color: var(--accent-line); box-shadow: var(--shadow-lg); }
/* Foto zur Bewertung: oben in der Karte, randlos, per Lightbox vergroesserbar */
.review-card.has-photo { padding-top: 0; }
.review-card.has-photo::before { display: none; }
.review-photo {
  display: block;
  margin: 0 -1.5rem .3rem;
  overflow: hidden;
  cursor: zoom-in;
}
/* height:auto ist Pflicht (siehe .work-img) */
.review-photo img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;   /* Nagelfotos sind fast immer hochkant */
  object-fit: cover;
  transition: transform .7s var(--ease);
}
.review-card:hover .review-photo img { transform: scale(1.04); }
.review-text {
  flex: 1;
  margin: 0;
  color: var(--color-text);
  font-size: 1rem;
  line-height: 1.65;
  overflow-wrap: anywhere;
}
.review-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem .75rem;
  padding-top: .9rem;
  border-top: 1px solid var(--line-soft);
}
.review-author { font-weight: 600; letter-spacing: -.01em; }
.review-foot .work-date { margin-left: auto; }
.review-form-title {
  margin: .4rem 0 .8rem;
  font-size: clamp(1.6rem, 3.5vw, 2.2rem);
  font-weight: 600;
  letter-spacing: -.03em;
  line-height: 1.1;
}
.review-notes { display: grid; gap: .55rem; margin: 1.4rem 0 0; padding: 0; list-style: none; }
.review-notes li { display: flex; align-items: flex-start; gap: .6rem; color: var(--color-text-muted); font-size: .92rem; line-height: 1.5; }
.review-notes svg { width: 1rem; height: 1rem; flex: none; margin-top: .2rem; color: var(--accent-ink); }

/* Sterne-Eingabe: DOM 5→1, row-reverse -- so faerbt "input:checked ~ label"
   genau die Sterne links vom gewaehlten (ohne JS). */
.rating-input {
  display: flex;
  flex-direction: row-reverse;
  justify-content: flex-end;
  gap: .1rem;
  width: fit-content;
}
.rating-input input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
.rating-input label {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 10px;
  cursor: pointer;
  transition: transform .2s var(--ease);
}
.rating-input label svg { width: 2rem; height: 2rem; color: var(--star-off); fill: var(--star-off); stroke: none; transition: color .2s, transform .2s var(--ease); }
.rating-input:hover input:checked ~ label svg { color: var(--star-off); fill: var(--star-off); }
.rating-input input:checked ~ label svg,
.rating-input label:hover svg,
.rating-input label:hover ~ label svg { color: var(--star); fill: var(--star); }
.rating-input label:hover svg { transform: scale(1.15); }
.rating-input input:focus-visible + label { outline: 2px solid var(--fokus-ring); outline-offset: 2px; }

/* Foto-Raster auf der Galerie-Detailseite: mehrere Bilder pro Arbeit,
   jedes mit Lightbox (die Lightbox gruppiert automatisch alle Links auf der
   Seite -- Vor/Zurueck blaettert so durch alle Fotos dieser Arbeit). */
.gallery-photos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: .85rem;
  margin: 1.5rem 0 2rem;
}
.gallery-photos.is-single {
  grid-template-columns: minmax(0, 1fr);
  max-width: 26rem;
}
.gallery-photos a {
  display: block;
  border-radius: var(--radius-lg);
  overflow: hidden;
  cursor: zoom-in;
}
.gallery-photos img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  transition: transform .5s var(--ease);
}
.gallery-photos a:hover img { transform: scale(1.04); }

/* ---------- TikTok-Feed (hochkant, wischbar wie in der App) ---------- */

.tiktok-feed {
  display: grid;
  gap: .7rem;
  justify-items: center;

  /* Diese Flaeche ist IMMER dunkel, egal welches Farbschema die Seite hat.
     Ohne diese Zeile bekaemen der Ton-Knopf und die Slide-Schalter im hellen
     Schema einen fast schwarzen Fokusrahmen auf schwarzem Grund. Da Variablen
     vererbt werden, reicht die eine Zeile fuer alles darin. */
  --fokus-ring: var(--fokus-ring-auf-dunkel);

  /* Der Streifen, der auf dem Handy tatsaechlich frei ist: Fenster
     minus klebender Kopfzeile (4.5rem), minus fester Aktionsleiste
     "Termin anfragen" (4.6rem), minus Hinweiszeile samt Abstand (3.4rem).
     Frueher stand hier schlicht 78vh -- ohne jeden Abzug. Ergebnis: die
     Karte war hoeher als der sichtbare Bereich, oben und unten
     angeschnitten. */
  --feed-max-h: calc(100vh - 4.5rem - 4.6rem - 3.4rem);
}

/* svh = kleine Viewport-Hoehe. 100vh ist auf Handys die Hoehe OHNE
   Adressleiste und damit groesser als das, was man wirklich sieht --
   genau der Grund, warum unten immer etwas fehlte. */
@supports (height: 100svh) {
  .tiktok-feed {
    --feed-max-h: calc(100svh - 4.5rem - 4.6rem - 3.4rem - env(safe-area-inset-bottom, 0px));
  }
}

.tiktok-feed-frame {
  position: relative;
  /* Der Rahmen hat GENAU das Format des Videos (1080x1920 = 9:16). Vorher
     kamen Breite und Hoehe aus zwei unabhaengigen Regeln, das Verhaeltnis
     passte nie exakt, und object-fit: cover hat den Rest weggeschnitten.
     Die dritte Groesse in min() deckelt die Breite so, dass die daraus
     folgende Hoehe in den freien Streifen passt. */
  width: min(100%, 420px, calc(var(--feed-max-h) * 9 / 16));
  aspect-ratio: 9 / 16;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: #0b090f;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
}

/* Der Scroll-Container: ein Video pro "Seite", das Einrasten macht das
   Wischen aus. scroll-snap ist bewusst mandatory -- halbe Videos wirken
   in einem solchen Feed wie ein Fehler. */
.tiktok-feed-track {
  /* Hoehe kommt jetzt vom Rahmen (9:16), nicht mehr aus einem eigenen
     vh-Wert -- damit koennen Rahmen und Track nicht mehr auseinanderlaufen. */
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* Bewusst NICHT "contain": das hat auf dem Handy jeden Ein-Finger-Wisch
     verschluckt (gemessen: Seite bewegte sich um 0 Pixel), weshalb man die
     Seite nur noch mit zwei Fingern verschieben konnte. Mit "auto" scrollt
     die Seite weiter, sobald der Feed am Anfang oder Ende steht. Das
     Einrasten von Video zu Video bleibt davon unberuehrt. */
  overscroll-behavior-y: auto;
}
.tiktok-feed-track::-webkit-scrollbar { display: none; }
/* --accent gibt es nicht (nur --color-accent, --accent-ink, ...). Ein
   ungueltiges var() macht die ganze Kurzschreibweise ungueltig: gemessen kam
   outline-style: none heraus -- der wischbare Feed war mit der Tastatur
   erreichbar und zeigte gar keinen Fokus. Die Flaeche ist immer dunkel. */
.tiktok-feed-track:focus-visible { outline: 2px solid var(--fokus-ring-auf-dunkel); outline-offset: -2px; }

.tiktok-slide {
  position: relative;
  height: 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  overflow: hidden;
  cursor: pointer;
}
.tiktok-slide-media { position: absolute; inset: 0; }
.tiktok-slide-poster { width: 100%; height: 100%; object-fit: cover; display: block; }
.tiktok-slide-player { position: absolute; inset: 0; }
.tiktok-slide-player iframe { width: 100%; height: 100%; border: 0; display: block; }

/* Sobald der Player steht, verschwindet das Vorschaubild dahinter. */
.tiktok-slide.is-loaded .tiktok-slide-poster { opacity: 0; transition: opacity .45s var(--ease); }

.tiktok-slide-shade {
  position: absolute; inset: auto 0 0 0; height: 38%;
  /* Heller als frueher (.82): man soll mehr vom Video sehen (Wunsch 17.09.2026). */
  background: linear-gradient(to bottom, rgba(11,9,15,0), rgba(11,9,15,.55));
  pointer-events: none;
}
.tiktok-slide-body {
  position: absolute; inset: auto 0 0 0;
  padding: 1rem 1.1rem 1.15rem;
  display: grid; gap: .55rem;
  color: #f7f2f8;
  pointer-events: none;
}
.tiktok-slide-body a, .tiktok-slide-body button { pointer-events: auto; }
/* Zugeklappt liegt sie gar nicht im Weg ([hidden]); aufgeklappt zeigt sie den
   VOLLEN Text und bekommt einen eigenen Hintergrund, damit sie ueber dem
   Video lesbar bleibt. Zu lange Texte scrollen in sich statt das Video zu
   ueberwachsen. */
.tiktok-slide-caption {
  margin: 0;
  /* Festes Mass statt Prozent: der Fuss ist absolut positioniert und hat
     selbst keine feste Hoehe -- eine Prozentangabe haette hier keinen
     verlaesslichen Bezug. 11rem sind rund acht Zeilen. */
  max-height: 11rem;
  overflow-y: auto;
  padding: .6rem .7rem;
  border-radius: var(--radius);
  background: rgba(11, 9, 15, .72);
  font-size: .92rem;
  line-height: 1.45;
  pointer-events: auto;
  overscroll-behavior: contain;
}
.tiktok-slide-actions { display: flex; align-items: center; gap: .6rem; justify-content: space-between; }

/* TikToks Player blendet unten seine eigene Leiste ein (Abspielen, Ton,
   Vollbild). Unsere Zeile weicht dann nach oben aus, sonst liegen beide
   uebereinander. Der Abdunkler unten wird flacher, damit TikToks Leiste
   nicht doppelt abgedunkelt wird. */
.tiktok-slide-buttons { display: flex; align-items: center; gap: .5rem; flex: none; }
.tiktok-slide-actions [data-tiktok-info][aria-expanded="true"] {
  background: var(--color-accent);
  border-color: var(--color-accent);
}
.tiktok-slide-link { color: #fff; font-size: .85rem; font-weight: 600; text-decoration: none; }
/* Knoepfe zu den Plattformen, auf denen das Video auch liegt (17.09.2026). */
.tiktok-slide-plattformen { display: flex; align-items: center; gap: .5rem; }
/* Musik-Nachweis (CC BY): dezent, als EINE Zeile ganz unten im Video
   (Wunsch 17.09.2026). Der Fuss rueckt dafuer naeher an die Unterkante, die
   Knoepfe bleiben etwa, wo sie waren. Die Zeile ist etwas breiter als die
   Knopfreihe (.6rem Rand statt 1.1rem) -- sie steht mittig wie im Video, und
   die runden Ecken des Rahmens (22px) schneiden auf dieser Hoehe nur gut
   7px ab. Schriftgroesse: siehe .tiktok-nachweis-zeile. */
.tiktok-slide-body.mit-nachweis { padding-bottom: .35rem; }
.tiktok-slide-musik {
  margin: .1rem -.5rem 0;
  /* Der Fuss ist ein Raster: Ohne min-width: 0 waere die Spalte mindestens so
     breit wie die ungekuerzte Zeile -- sie ragte ueber den Rahmen hinaus, und
     jede Aenderung der Schrift aenderte die Breite gleich mit. */
  min-width: 0;
  color: rgba(255, 255, 255, .5);
  text-align: center;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .45);
  /* Der Fuss laesst Tipps zum Video durch; der Nachweis nimmt sie an, damit
     die Maus den vollen Wortlaut (title) zeigt. Ein Tipp darauf haelt das
     Video trotzdem an -- das Ereignis landet beim Slide. */
  pointer-events: auto;
  font-size: .64rem;
  /* Gemessen (17.09.2026, Chrome, Zeile = Rahmen minus 1.2rem). ACHTUNG: Die
     Breite der Zeile haengt nicht nur an der Fensterbreite, sondern vor allem
     an der HOEHE -- der Rahmen ist min(100%, 420px, Hoehe * 9/16). Auf einem
     echten Handy mit Adressleiste ist sie deshalb deutlich schmaler als bei
     gleicher Breite ohne Leisten. Darum steht hier immer BREITE x HOEHE:
       390x844  -> Zeile 330 px, voller Nachweis in 10.24px
       412x783  -> Zeile 307 px, voller Nachweis in 9.99px
       1280x800 -> Zeile 348 px, voller Nachweis in 10.24px
       390x664 (iPhone 13 mit Leisten) -> Zeile 240 px, 8px, Titel gekuerzt
       393x659  -> Zeile 237 px, 8px, Titel gekuerzt
       360x668  -> Zeile 242 px, 8px, Titel gekuerzt
       360x640  -> Zeile 226 px, 8px, Titel gekuerzt
       375x553 (iPhone SE) -> Zeile 177 px, 8px, ohne Titel
       320x568  -> Zeile 186 px, 8px, ohne Titel
     Ein Nachweis von incompetech ist rund 30 Schriftgroessen breit, ohne
     Titel rund 21. "Passt ganz" gilt also erst ab etwa 310 px ZEILENbreite --
     nicht schon ab 360 px Fensterbreite. Unter 8px wird es muehsam: nur wenn
     Urheber und Lizenz ohne Titel noch zu lang sind, geht es bis 6px. */
  --nachweis-min: 8px;
  --nachweis-not: 6px;
  transition: opacity .3s var(--ease);
}
.tiktok-slide-musik .tiktok-nachweis-zeile { height: .9rem; line-height: .9rem; }

/* In den letzten 3,5 Sekunden schreibt der Generator den Nachweis INS Video
   (admin-tiktok-generator.js: NACHWEIS_SEKUNDEN) -- genau dorthin, wo die
   Zeile der Seite liegt: gemessen bei 390x844 beide 16-21 px ueber der
   Rahmenunterkante, die Buchstaben beruehren sich. Solange der eingebrannte
   Nachweis steht, tritt die Zeile der Seite deshalb zurueck (eigener-feed.js
   setzt die Klasse ueber nachweisImVideo). Im Vorlesebaum aendert sich
   nichts: der volle Wortlaut daneben bleibt. */
.tiktok-slide.nachweis-im-video .tiktok-slide-musik { opacity: 0; }

/* Die eine Zeile selbst, fuer Feed und Kachel (nachweis-zeile.js). Ohne
   JavaScript bleibt sie ebenfalls eine Zeile und endet mit … -- nie ein
   Umbruch. Die feste Hoehe (je Stelle) haelt die Zeile gleich hoch, egal
   welche Schrift das Skript waehlt: nichts springt, und der ResizeObserver
   meldet sich nicht nach jeder eigenen Aenderung neu. */
.tiktok-nachweis-zeile {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.tiktok-nachweis-zeile.wird-eingepasst { text-overflow: clip; }
.tiktok-slide-link:hover { color: var(--accent-auf-dunkel); }
.tiktok-slide-actions .icon-btn {
  width: 2.4rem; height: 2.4rem; flex: none;
  /* Halb durchsichtig, damit das Video durchscheint; beim Zeigen deutlicher. */
  background: rgba(11,9,15,.28); border-color: rgba(255,255,255,.18); color: rgba(255,255,255,.88);
}
.tiktok-slide-actions .icon-btn:hover,
.tiktok-slide-actions .icon-btn:focus-visible { background: rgba(11,9,15,.55); color: #fff; }

/* Puffert das Video (schwaches Netz), dreht sich ein Ring -- sonst sieht man
   im Vollbild nur ein stehendes Titelbild und haelt den Player fuer kaputt.
   Gleiche Machart wie das Ladezeichen der Startseiten-Kachel. */
.tiktok-slide.is-laedt::before {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .3);
  border-top-color: #fff;
  animation: tiktok-card-dreh .8s linear infinite;
  pointer-events: none;
}
/* Weniger Bewegung: ruhender, voller Ring statt Dauerschleife -- mit
   data-motion und ohne JavaScript. */
html[data-motion="calm"] .tiktok-slide.is-laedt::before {
  animation: none;
  border-color: rgba(255, 255, 255, .85);
}
@media (prefers-reduced-motion: reduce) {
  html:not([data-motion]) .tiktok-slide.is-laedt::before { animation: none; border-color: rgba(255, 255, 255, .85); }
}

/* Pause-Zeichen, wenn angetippt wurde */
.tiktok-slide.is-paused::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 4.5rem; height: 4.5rem; border-radius: 50%;
  background: rgba(11,9,15,.5) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23fff'%3E%3Cpath d='M8 5v14l11-7z'/%3E%3C/svg%3E") center/2rem no-repeat;
  pointer-events: none;
}

/* Zustimmungsschicht: bis dahin ist kein iframe im DOM. */
.tiktok-feed-consent {
  position: absolute; inset: 0; z-index: 2;
  display: grid; place-items: center;
  padding: 1.4rem;
  background: linear-gradient(180deg, rgba(11,9,15,.72), rgba(11,9,15,.92));
  backdrop-filter: blur(3px);
}
.tiktok-feed-consent-inner { text-align: center; display: grid; gap: .7rem; justify-items: center; color: #f7f2f8; }
.tiktok-feed-consent-inner h3 { margin: 0; font-size: 1.15rem; color: #fff; }
.tiktok-feed-consent-inner p { margin: 0; font-size: .86rem; line-height: 1.5; color: rgba(247,242,248,.82); }
.tiktok-feed-consent-note { font-size: .78rem !important; }
.tiktok-feed-consent-note a { color: var(--accent-auf-dunkel); }

.tiktok-feed-sound {
  position: absolute; top: .8rem; right: .8rem; z-index: 3;
  border: 1px solid rgba(255,255,255,.2);
  background: rgba(11,9,15,.32); color: #fff;
  border-radius: 999px; padding: .4rem .85rem;
  font: inherit; font-size: .78rem; font-weight: 600;
  cursor: pointer;
}
.tiktok-feed-sound:hover { background: rgba(11,9,15,.8); }

.tiktok-feed-hint { margin: 0; font-size: .8rem; color: var(--muted); text-align: center; }

/* Auf grossen Bildschirmen darf die Karte etwas hoeher werden -- der
   Rahmen rechnet die Breite ueber das 9:16-Verhaeltnis selbst nach. */
@media (min-width: 900px) {
  .tiktok-feed { --feed-max-h: min(82vh, 860px); }
}

/* Hat das Video nachweislich keine Tonspur, sagt der Knopf das ehrlich,
   statt einen Ton zu versprechen, den es nicht gibt. */
.tiktok-feed-sound[disabled] {
  opacity: .65;
  cursor: default;
}

/* ---------- Vollbild-Player am Handy (18.09.2026) ----------
   Wunsch von Matthias: wie in der App. Nach dem Start legt sich der Feed ueber
   die ganze Seite -- nur Video, Knoepfe, Ton und ein X (eigener-feed.js).
   Kein echter Vollbildmodus des Browsers: den gibt es auf dem iPhone nur fuer
   das <video> selbst, ohne unsere Knoepfe und ohne Wischen.
   Ebene 55: ueber Kopfzeile (50) und Leiste "Termin anfragen" (40), unter dem
   Hinweis "Link kopiert" (60) -- den braucht der Teilen-Knopf im Player. */
.tiktok-feed[hidden] { display: none; }

body.vollbild-offen { overflow: hidden; }

.tiktok-feed.ist-vollbild {
  position: fixed;
  inset: 0;
  z-index: 55;
  display: block;
  background: #0b090f;
}

.tiktok-feed.ist-vollbild .tiktok-feed-frame {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* Das Video GANZ zeigen, wie die App auf hohen Handys: dunkler Rand oben und
   unten statt abgeschnittener Seiten. Mit "cover" fehlten links und rechts
   Teile der Schrift im Video -- und des eingebrannten Musik-Nachweises. Das
   Titelbild genauso, sonst springt das Bild, wenn das Video anlaeuft. */
.tiktok-feed.ist-vollbild .tiktok-slide-poster,
.tiktok-feed.ist-vollbild .tiktok-slide-player video { object-fit: contain; }

/* Hier darf "contain" sein (eingebettet bewusst nicht, siehe oben): Wischen
   am ersten oder letzten Video bewegt nicht die Seite dahinter und loest
   oben nicht "Neu laden" aus. */
.tiktok-feed.ist-vollbild .tiktok-feed-track { overscroll-behavior-y: contain; }

/* Kerbe, Kamera-Loch und Home-Balken des Handys freihalten. */
.tiktok-feed.ist-vollbild .tiktok-slide-body {
  padding-right: max(1.1rem, env(safe-area-inset-right, 0px));
  padding-bottom: calc(1.15rem + env(safe-area-inset-bottom, 0px));
  padding-left: max(1.1rem, env(safe-area-inset-left, 0px));
}
.tiktok-feed.ist-vollbild .tiktok-slide-body.mit-nachweis { padding-bottom: calc(.35rem + env(safe-area-inset-bottom, 0px)); }
.tiktok-feed.ist-vollbild .tiktok-feed-sound {
  top: calc(.8rem + env(safe-area-inset-top, 0px));
  right: calc(.8rem + env(safe-area-inset-right, 0px));
}

/* Das X: oben links, gleiche Machart wie der Ton-Knopf gegenueber. */
.tiktok-feed-schliessen {
  position: absolute;
  top: calc(.8rem + env(safe-area-inset-top, 0px));
  left: calc(.8rem + env(safe-area-inset-left, 0px));
  z-index: 3;
  display: grid;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  padding: 0;
  border: 1px solid rgba(255,255,255,.2);
  border-radius: 50%;
  background: rgba(11,9,15,.32);
  color: #fff;
  cursor: pointer;
}
.tiktok-feed-schliessen[hidden] { display: none; }
.tiktok-feed-schliessen .icon { width: 1.3rem; height: 1.3rem; }
.tiktok-feed-schliessen:hover { background: rgba(11,9,15,.8); }
.tiktok-feed-schliessen:focus-visible { outline: 2px solid var(--fokus-ring-auf-dunkel); outline-offset: 2px; }

/* "Nach oben wischen" als Pille im Bild, die nach ein paar Sekunden geht --
   unter dem Rahmen wie am Rechner ist im Vollbild kein Platz. */
.tiktok-feed.ist-vollbild .tiktok-feed-hint {
  position: absolute;
  top: 58%;
  left: 50%;
  z-index: 3;
  width: max-content;
  max-width: calc(100% - 3rem);
  padding: .55rem 1rem;
  border-radius: 999px;
  background: rgba(11,9,15,.72);
  color: #fff;
  font-weight: 600;
  transform: translateX(-50%);
  pointer-events: none;
}
.tiktok-feed-hint.blendet-aus { animation: vollbild-hinweis 3.6s var(--ease) forwards; }
@keyframes vollbild-hinweis {
  0%, 78% { opacity: 1; }
  100% { opacity: 0; }
}

/* ---------- TikTok ---------- */

.tiktok-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .85rem;
}
.tiktok-card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel);
  overflow: hidden;
  transition: transform .4s var(--ease), border-color .35s, box-shadow .4s;
}
.tiktok-card:hover { transform: translateY(-6px); border-color: var(--accent-line); box-shadow: var(--shadow-lg); }

/* Vorschaubild + Abspiel-Knopf: solange nichts geklickt wurde, gab es keinen
   Kontakt zu TikTok (dEVIL_TikTok.md Abschnitt 8) -- das Bild liegt lokal. */
.tiktok-thumb {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 9 / 16;
  border: 0;
  padding: 0;
  margin: 0;
  background: var(--color-surface);
  color: inherit;
  cursor: pointer;
  overflow: hidden;
}
.tiktok-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s var(--ease);
}
.tiktok-card:hover .tiktok-thumb img { transform: scale(1.04); }
.tiktok-thumb::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(17, 13, 23, .1) 40%, rgba(17, 13, 23, .75));
  pointer-events: none;
}
.tiktok-play-icon {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 3.4rem;
  height: 3.4rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, .16);
  backdrop-filter: blur(6px);
  color: #fff;
  transition: transform .3s var(--ease), background-color .3s, opacity .25s;
}
.tiktok-play-icon svg { width: 1.6rem; height: 1.6rem; }
.tiktok-card:hover .tiktok-play-icon { transform: scale(1.08); background: var(--color-accent); }

/* Abspielen direkt in der Kachel (startseite-videos.js, 17.09.2026).
   Die Kachel ist ein Rahmen, der Link steckt darin -- daneben liegt waehrend
   des Abspielens der Ton-Knopf (ein Knopf darf nicht in einem Link liegen). */
.tiktok-card { position: relative; }
.tiktok-card-link {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  color: inherit;
  text-decoration: none;
}
/* Fokus: Der Rahmen der ganzen Kachel statt eines abgeschnittenen Rings am
   Link (die Kachel schneidet mit overflow: hidden alles ab, was uebersteht).
   Browser ohne :has() behalten einen Ring innen am Link. */
.tiktok-card-link:focus-visible { outline-offset: -4px; }
.tiktok-card:has(.tiktok-card-link:focus-visible) { outline: 2px solid var(--fokus-ring); outline-offset: 3px; }
.tiktok-card:has(.tiktok-card-link:focus-visible) .tiktok-card-link:focus-visible { outline: none; }

/* Das eine Video-Element liegt ueber dem Titelbild und wird erst sichtbar,
   wenn es wirklich ein Bild zeigt -- kein schwarzes Aufblitzen. */
.tiktok-card-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  background: #0b090f;
  opacity: 0;
  transition: opacity .3s;
}
.tiktok-card.is-loaded .tiktok-card-video { opacity: 1; }
.tiktok-thumb::after { transition: opacity .3s; }
.tiktok-card.is-loaded .tiktok-thumb::after { opacity: 0; }

/* Laeuft: Play-Symbol weg. Laedt noch: an seiner Stelle ein Ring. */
.tiktok-card.is-playing .tiktok-play-icon { opacity: 0; }
.tiktok-card.is-playing.is-laedt .tiktok-play-icon { opacity: 1; }
.tiktok-card.is-laedt .tiktok-play-icon svg { opacity: 0; }
.tiktok-card.is-laedt .tiktok-play-icon::before {
  content: "";
  position: absolute;
  inset: .9rem;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .3);
  border-top-color: #fff;
  animation: tiktok-card-dreh .8s linear infinite;
}
@keyframes tiktok-card-dreh { to { transform: rotate(360deg); } }
/* Weniger Bewegung: Der Ring ist eine Dauerschleife, also ganz aus (wie im
   Abschnitt "Weniger Bewegung" unten) -- stattdessen ein ruhender, voller Ring.
   Beide Faelle gleich: mit data-motion und ohne JavaScript. */
html[data-motion="calm"] .tiktok-card.is-laedt .tiktok-play-icon::before {
  animation: none;
  border-color: rgba(255, 255, 255, .85);
}
@media (prefers-reduced-motion: reduce) {
  html:not([data-motion]) .tiktok-card.is-laedt .tiktok-play-icon::before { animation: none; border-color: rgba(255, 255, 255, .85); }
}

/* Fortschritt: duenner Balken an der Unterkante des Bildes. */
.tiktok-card-fortschritt {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: rgba(255, 255, 255, .22);
  pointer-events: none;
}
.tiktok-card-fortschritt > span {
  display: block;
  height: 100%;
  background: var(--color-accent);
  transform: scaleX(0);
  transform-origin: left center;
}

/* Ton an/aus: oben rechts im laufenden Video. Die Flaeche darunter ist
   immer das Video, also Fokusring fuer dunklen Grund. */
.tiktok-card-ton {
  --fokus-ring: var(--fokus-ring-auf-dunkel);
  position: absolute;
  top: .5rem;
  right: .5rem;
  z-index: 2;
  width: 2.6rem;
  height: 2.6rem;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 50%;
  background: rgba(11, 9, 15, .42);
  color: #fff;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.tiktok-card-ton:hover { background: rgba(11, 9, 15, .72); }
.tiktok-card-ton .icon { width: 1.2rem; height: 1.2rem; }
.tiktok-card-ton .ton-aus,
.tiktok-card-ton.ist-stumm .ton-an { display: none; }
.tiktok-card-ton.ist-stumm .ton-aus { display: block; }

/* Musik-Nachweis (CC BY) als EINE Zeile unten ueber dem Bild, direkt ueber
   dem Fortschrittsbalken (17.09.2026). Frueher stand er unter dem Titel, brach
   auf dem Handy auf vier Zeilen um und hielt nach dem Abspielen seinen Platz
   frei. Jetzt liegt er ueber dem Bild: kein Platz im Kartenkoerper, nichts
   springt. Zu sehen nur, solange das Video in der Kachel ein Bild zeigt --
   laufend oder angehalten (is-loaded, startseite-videos.js). Unsichtbar per
   visibility statt display: Die Zeile behaelt ihre Breite, und
   nachweis-zeile.js kann sie schon vorher einpassen. */
.tiktok-card-musik {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /* Unten Platz fuer den 3px-Balken, oben Auslauf fuer den Verlauf. */
  padding: .9rem .35rem calc(3px + .2rem);
  background: linear-gradient(to bottom, rgba(11, 9, 15, 0), rgba(11, 9, 15, .6));
  color: rgba(255, 255, 255, .78);
  text-align: center;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .5);
  visibility: hidden;
  opacity: 0;
  transition: opacity .3s, visibility 0s linear .3s;
  font-size: .6rem;
  /* Gemessen (17.09.2026, Chrome, Zeile = Kachel minus .7rem): 320 px
     Fenster -> 122 px Zeile, 360 -> 142, 390 -> 156, Desktop 1280 -> 230.
     Die Kachel steht im Raster der Startseite, ihre Breite haengt also am
     Fenster (anders als im Feed, wo die Hoehe entscheidet).
     Ein Nachweis von incompetech ist rund 30 Schriftgroessen breit, ohne
     Titel rund 21. Auf dem Desktop passt er ganz (7.5px). Auf dem Handy
     reicht die Kachel dafuer nicht: Der Titel faellt weg, Urheber und Lizenz
     stehen in 7px (390), 6.5px (360) oder 5.5px (320) -- klein, aber
     vollstaendig, und gross steht alles auf /videos. Unter 5px geht es nie. */
  --nachweis-min: 7px;
  --nachweis-not: 5px;
}
.tiktok-card-musik .tiktok-nachweis-zeile { height: .8rem; line-height: .8rem; }
.tiktok-card.is-loaded .tiktok-card-musik {
  visibility: visible;
  opacity: 1;
  transition: opacity .3s;
}

/* Reicht selbst die Notgrenze nicht (ein Nachweis ohne erkennbaren Titel,
   etwa "♪ Kevin MacLeod – Gentle Thoughts …", oder ein sehr langer Urheber),
   bliebe in der schmalen Kachel nur ein mit … abgeschnittener Stummel: Der
   nennt weder Urheber noch Lizenz vollstaendig und nuetzt niemandem. Dann
   zeigt die Kachel lieber gar nichts -- eingebrannt steht der Nachweis im
   Video, in voller Groesse auf /videos, und Vorleseprogramme bekommen ihn
   hier weiter als Beschreibung des Links (startseite-videos.js). Der Verlauf
   geht mit, sonst laege ein dunkler Balken ueber nichts.
   Im Feed ist das anders: dort ist Platz, und … am Ende einer breiten Zeile
   verraet immer noch, worum es geht. */
.tiktok-card-musik > .tiktok-nachweis-zeile.ist-zu-lang { visibility: hidden; }
.tiktok-card-musik:has(> .tiktok-nachweis-zeile.ist-zu-lang) { background: none; }

/* Wie im Feed: In den letzten 3,5 Sekunden steht der Nachweis eingebrannt im
   Video, auf derselben Hoehe wie die Zeile der Seite. Dann tritt sie zurueck
   (startseite-videos.js setzt die Klasse ueber nachweisImVideo). Eine Klasse
   mehr als die is-loaded-Regel darueber, damit sie gewinnt. */
.tiktok-card.is-loaded.nachweis-im-video .tiktok-card-musik { opacity: 0; }
.tiktok-load-hint {
  position: absolute;
  left: .8rem;
  right: .8rem;
  bottom: .7rem;
  color: #fff;
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-align: center;
}

/* Sobald geladen: das offizielle TikTok-Embed uebernimmt Breite/Hoehe selbst. */
.tiktok-card .tiktok-thumb, .tiktok-card .tiktok-card-body { display: block; }

.tiktok-embed-slot blockquote.tiktok-embed { margin: 0 auto !important; }

.tiktok-card-body { padding: .9rem 1rem 1rem; display: grid; gap: .6rem; }
.tiktok-card-body p,
.tiktok-card-body span {
  margin: 0;
  color: var(--color-text-muted);
  font-size: .88rem;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.tiktok-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
}
.tiktok-card-foot a {
  color: var(--color-text);
  font-family: var(--mono);
  font-size: .74rem;
  letter-spacing: .06em;
  text-decoration: none;
}
.tiktok-card-foot a:hover { color: var(--accent-ink); }
.tiktok-card-foot .icon-btn { width: 2.4rem; height: 2.4rem; flex: none; }
.tiktok-card-foot .icon-btn svg { width: 1rem; height: 1rem; }

@media (min-width: 700px) {
  .tiktok-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1100px) {
  .tiktok-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ---------- Rechtsseiten ---------- */

.legal { padding: clamp(2.5rem, 6vw, 4.5rem) 0 clamp(3rem, 6vw, 5rem); }
.back-link {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  margin-bottom: 1.5rem;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .78rem;
  letter-spacing: .06em;
  text-decoration: none;
}
.back-link:hover { color: var(--accent-ink); }
.legal-head { margin-bottom: clamp(2rem, 5vw, 3rem); }
.blog-article-meta {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin-bottom: .9rem;
}
.blog-article-cover {
  width: 100%;
  height: auto;
  max-height: 34rem;
  object-fit: cover;
  border-radius: var(--radius-lg);
  margin: 1.5rem 0 2rem;
}
.legal-head h1 {
  max-width: 18ch;
  margin: 0 0 .8rem;
  font-size: clamp(2.2rem, 5vw, 3.6rem);
  font-weight: 600;
  letter-spacing: -.045em;
  line-height: 1.04;
}
.legal-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2.5rem;
  align-items: start;
}
.toc {
  padding: 1.3rem 1.4rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel);
}
.toc h2 {
  margin: 0 0 .9rem;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .68rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.toc ol { display: grid; gap: .45rem; margin: 0; padding: 0; list-style: none; counter-reset: toc; }
.toc li { counter-increment: toc; }
.toc a {
  display: flex;
  gap: .6rem;
  color: var(--color-text-muted);
  font-size: .88rem;
  line-height: 1.4;
  text-decoration: none;
  transition: color .2s, transform .2s var(--ease);
}
.toc a::before {
  content: counter(toc, decimal-leading-zero);
  flex: none;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .72rem;
  line-height: 1.7;
}
.toc a:hover { color: var(--accent-ink); transform: translateX(3px); }

.legal-body { max-width: 72ch; }
.legal-body section {
  padding: 1.8rem 0;
  border-top: 1px solid var(--line-soft);
  scroll-margin-top: 6rem;
}
.legal-body section:first-child { padding-top: 0; border-top: 0; }
.legal-body h2 { margin: 0 0 .8rem; font-size: 1.25rem; font-weight: 600; letter-spacing: -.02em; }
.legal-body p, .legal-body li { color: var(--color-text-muted); font-size: .97rem; line-height: 1.75; }
.legal-body ul { margin: 0 0 1.1em; padding-left: 1.2rem; }
.legal-body li { margin-bottom: .35rem; }
.legal-body a { color: var(--color-text); text-decoration-color: var(--accent-line); text-underline-offset: .25em; }
.legal-body a:hover { color: var(--accent-ink); }
.legal-updated {
  margin-top: 2.5rem;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .74rem;
  letter-spacing: .06em;
}

/* ---------- Fusszeile ---------- */

.site-footer { padding: clamp(2rem, 5vw, 4rem) 0 1.5rem; }
/* Das Panel bleibt in beiden Schemata dunkel (Logo mit weissen Buchstaben) –
   die Text-Tokens werden dafuer lokal ueberschrieben. */
.footer-panel {
  --color-text: #f7f2f8;
  --color-text-muted: #b9aec6;
  --dim: #948aa0;
  --line: rgba(255, 255, 255, .1);
  --line-soft: rgba(255, 255, 255, .07);
  --panel: rgba(255, 255, 255, .04);
  --accent-ink: #ff5aa5;
  position: relative;
  padding: clamp(2rem, 5vw, 3.5rem) clamp(1.25rem, 4vw, 3rem) 1.5rem;
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: calc(var(--radius-lg) + 8px);
  background:
    radial-gradient(40rem 18rem at 92% -20%, rgba(230, 25, 122, .24), transparent 70%),
    radial-gradient(30rem 16rem at 0% 110%, rgba(var(--season-rgb), .18), transparent 70%),
    linear-gradient(170deg, #1d1727, #120e18 60%);
  color: var(--color-text);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2rem;
  margin-bottom: 2.5rem;
}
.footer-logo { display: inline-block; border-radius: 12px; }
.footer-logo img { width: min(100%, 15rem); height: auto; }
.footer-brand p { max-width: 34ch; margin: 1.1rem 0 0; color: var(--color-text-muted); font-size: .92rem; }
.footer-col h3 {
  margin: 0 0 .9rem;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .68rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.footer-col ul { display: grid; gap: .3rem; margin: 0; padding: 0; list-style: none; }
.footer-col a {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .3rem 0;   /* groessere Tippflaeche, gleicher Zeilenabstand */
  color: var(--color-text-muted);
  font-size: .93rem;
  text-decoration: none;
  transition: color .2s, transform .2s var(--ease);
}
.footer-col a:hover { color: #fff; transform: translateX(3px); }

/* Am Handy sind das die einzigen Links im Fussbereich, und mit 33 px Hoehe
   trifft man sie mit dem Daumen schlecht. Nur fuer grobe Zeigegeraete, damit
   die Spalte am Rechner kompakt bleibt. (pointer: coarse) trifft Finger,
   nicht Fenstergroesse -- ein schmales Browserfenster am Rechner bleibt eng.) */
@media (pointer: coarse) {
  .footer-col a { padding: .65rem 0; }
}
.footer-col a svg { width: .95rem; height: .95rem; color: var(--accent-ink); }
.footer-col address { margin: 0; font-style: normal; color: var(--color-text-muted); font-size: .93rem; line-height: 1.7; }
.footer-col address strong { color: var(--color-text); }

/* Seitenliste im Fuss: am Handy nur die Rechtsseiten, der Rest ueber "Mehr".
   Zugeklappt wird ausschliesslich ueber .footer-seiten-zu, die site.js setzt
   -- ohne Skript bleibt die Liste vollstaendig. */
.footer-mehr-knopf {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  margin-top: .35rem;
  padding: .65rem 0;
  border: 0;
  background: none;
  color: var(--accent-ink);
  font: inherit;
  font-size: .93rem;
  cursor: pointer;
}
.footer-mehr-knopf .arrow { width: .95rem; height: .95rem; transform: rotate(90deg); transition: transform .3s var(--ease); }
.footer-mehr-knopf[aria-expanded="true"] .arrow { transform: rotate(-90deg); }
.footer-seiten-zu .footer-seite-mehr { display: none; }

@media (min-width: 760px) {
  /* Am Rechner ist Platz: alles offen, und die Inhaltsseiten wieder vor den
     Rechtsseiten wie bisher. */
  .footer-seiten-zu .footer-seite-mehr { display: list-item; }
  .footer-seite-mehr { order: -1; }
  .footer-mehr-knopf { display: none; }
}
.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .75rem 1.5rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--line-soft);
  color: var(--dim);
  font-size: .82rem;
}
.privacy-badge {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .06em;
}
.privacy-badge svg { width: .95rem; height: .95rem; color: var(--accent-ink); }

/* ---------- Scroll-Animation (nur mit JS aktiv) ---------- */

.js .reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .75s var(--ease), transform .75s var(--ease);
  transition-delay: var(--rd, 0s);
}
.js .reveal.is-visible { opacity: 1; transform: none; }
/* Sicherheitsnetz: Kommt site.js nicht zum Zug (blockiert, Ladefehler,
   Syntaxfehler in altem Browser), fehlt html.js-ready – dann werden die
   Bloecke nach 1.5 s ohne Scroll-Logik eingeblendet. */
.js:not(.js-ready) .reveal { animation: reveal-fallback 0s linear 1.5s forwards; }
@keyframes reveal-fallback { to { opacity: 1; transform: none; } }

/* ---------- Breakpoints ---------- */

@media (min-width: 520px) {
  .address-input-row { grid-template-columns: minmax(0, 1fr) auto; }
}

@media (min-width: 620px) {
  .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .field.is-wide { grid-column: 1 / -1; }
}

@media (min-width: 700px) {
  .facts { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .steps { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .work-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.1rem; }
  .review-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1000px) {
  .review-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 760px) {
  .action-bar, .action-bar-spacer { display: none; }
  .section-head {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
    align-items: end;
    gap: 1.5rem 4rem;
  }
  .cta { grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
  .footer-grid { grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr)); gap: 2.5rem; }
}

@media (min-width: 860px) {
  .site-nav { display: flex; }
  .menu-toggle { display: none; }
  .mobile-menu { display: none !important; }
  .about-grid { grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); gap: 4.5rem; }
  .portrait { margin: 0; }
}

@media (min-width: 900px) {
  .hero-grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); }
  .legal-layout { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); gap: 4rem; }
  .toc { position: sticky; top: 6rem; }
}

@media (min-width: 960px) {
  /* Formular links und breit, Kontaktwege rechts -- dieselbe Reihenfolge
     wie auf dem Handy, wo das Formular seit dem 13.09.2026 zuerst kommt. */
  .contact-layout { grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr); gap: 4rem; }
  .contact-aside { position: sticky; top: 6rem; }
}

@media (min-width: 1100px) {
  .work-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .work-grid.is-featured { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 519px) {
  .header-cta { display: none; }
  .hero-actions .btn { flex: 1 1 auto; }
  .cta-actions .btn { width: 100%; }
}

/* ---------- Weniger Bewegung ----------
   Das Geraet kann "Bewegung reduzieren" verlangen: iOS Bedienungshilfen >
   Bewegung, Android Bedienungshilfen > Animationen entfernen -- und auf
   vielen Handys schaltet das der Energiesparmodus automatisch mit ein.
   Frueher hat dieser Block per *-Selektor mit !important JEDE Animation und
   JEDEN Uebergang abgewuergt; die Seite stand dann komplett still, inklusive
   Wortwechsel in der Hero-Zeile und jedem Einblenden beim Scrollen.
   Jetzt bleibt erhalten, was fuer empfindliche Augen unbedenklich ist --
   reine Deckkraft-Wechsel -- und es faellt nur weg, was tatsaechlich stoert:
   grosse Verschiebungen, Zoomfahrten und Dauerschleifen. */

@keyframes fade-soft { from { opacity: 0; } to { opacity: 1; } }

/* Fall 1 -- ohne JavaScript: Das Kopf-Script konnte data-motion nicht setzen,
   also gilt unmittelbar die Geraeteeinstellung. Hier nur das Noetigste, naemlich
   die Dauerschleifen; alles Weitere braucht ohnehin JavaScript. */
@media (prefers-reduced-motion: reduce) {
  html:not([data-motion]) { scroll-behavior: auto; }
  html:not([data-motion]) .hero-logo,
  html:not([data-motion]) .hero-photo,
  html:not([data-motion]) .sparkle,
  html:not([data-motion]) .status .dot::after,
  html:not([data-motion]) .hero-visual::before,
  html:not([data-motion]) .hero-visual::after { animation: none !important; }
  html:not([data-motion]) .hero-photo { transform: none; }
  /* Der Saison-Flug ist reine Dauerbewegung. Stehende Punkte waeren kein
     Ersatz, sondern nur Flecken -- deshalb ganz weg. */
  html:not([data-motion]) .saison-flug { display: none !important; }
}

/* Fall 2 -- der Normalfall: data-motion am <html>-Tag entscheidet. Es kommt
   entweder von der Geraeteeinstellung oder von der ausdruecklichen Wahl der
   Besucherin ueber den Bewegungs-Knopf (layout.twig, site.js). Steht dort
   "full", laeuft alles -- auch wenn das Geraet weniger Bewegung verlangt. */
html[data-motion="calm"] { scroll-behavior: auto; }

/* Dauerschleifen und Zoomfahrten: ganz aus. */
html[data-motion="calm"] .hero-logo,
html[data-motion="calm"] .hero-photo,
html[data-motion="calm"] .sparkle,
html[data-motion="calm"] .status .dot::after,
html[data-motion="calm"] .hero-visual::before,
html[data-motion="calm"] .hero-visual::after { animation: none !important; }
html[data-motion="calm"] .hero-photo { transform: none; }
html[data-motion="calm"] .sparkle { opacity: .8; transform: none; }
/* Siehe oben: stehende Punkte waeren kein Ersatz, sondern Flecken. */
html[data-motion="calm"] .saison-flug { display: none !important; }

/* Einmalige Einblendungen: gleiche Wirkung, aber ohne Weg. */
html[data-motion="calm"] .hero-visual,
html[data-motion="calm"] .hero-in,
html[data-motion="calm"] .hero h1 .line > span {
  animation-name: fade-soft !important;
  animation-duration: .5s !important;
}

/* Einblenden beim Scrollen bleibt -- nur ohne Anheben.
   Achtung: .js sitzt am <html>-Element selbst, deshalb ohne Leerzeichen. */
html[data-motion="calm"].js .reveal {
  transform: none !important;
  transition: opacity .35s linear !important;
}

/* Der Wortwechsel bleibt: reine Ueberblendung, keine Verschiebung. */
html[data-motion="calm"] .rotor > span,
html[data-motion="calm"] .rotor > span.is-leaving {
  transform: none !important;
  transition: opacity .35s linear !important;
}

/* Alles Uebrige (Karten, Knoepfe, Menue) faehrt kurz statt gar nicht --
   sonst fehlt jede Rueckmeldung auf Antippen. */
html[data-motion="calm"] *,
html[data-motion="calm"] *::before,
html[data-motion="calm"] *::after {
  transition-duration: .12s;
  transition-delay: 0s;
}

/* Der Bewegungs-Knopf blendet sich selbst ein (site.js) und ist nur dort
   sichtbar, wo das Geraet ueberhaupt weniger Bewegung verlangt.

   In der Kopfzeile stand er lange als blosses Sternchen -- verstanden hat ihn
   niemand ("was ist das Symbol?"). Deshalb jetzt mit Text, und auf schmalen
   Schirmen gar nicht mehr dort: im Menue steht derselbe Schalter, dort ist
   Platz fuer die Beschriftung. */
.motion-toggle[aria-pressed="true"] { color: var(--accent-ink); }

.site-header .motion-toggle { display: none; }

@media (min-width: 860px) {
  /* :not([hidden]) respektiert die Steuerung aus site.js -- ohne
     Geraetewunsch nach Ruhe bleibt der Knopf weg. */
  .site-header .motion-toggle:not([hidden]) {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    min-height: 2.75rem;
    padding: .35rem .95rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--panel);
    color: var(--color-text-muted);
    font: inherit;
    font-size: .84rem;
    font-weight: 500;
    cursor: pointer;
  }
  .site-header .motion-toggle:hover { border-color: var(--accent-line); color: var(--accent-ink); }
  .site-header .motion-toggle svg { width: 18px; height: 18px; }
}

/* Im Menue traegt der Knopf den Text ohnehin -- dort nichts ausblenden. */
.mobile-menu .motion-toggle-text { display: inline; }

/* ---------- Touch: Rueckmeldung beim Antippen ----------
   Auf dem Handy ist (hover: hover) falsch, die rund 40 :hover-Regeln greifen
   dort also nie -- ohne Ersatz fuehlt sich jedes Tippen tot an. Zwei Dinge
   passieren hier: erstens wird der von iOS Safari "klebend" vergebene
   Hover-Zustand neutralisiert (sonst bleibt eine Karte angehoben stehen, bis
   woanders hingetippt wird), zweitens gibt es echte :active-Zustaende.
   Die :active-Regeln stehen bewusst NACH den Neutralisierungen -- beim Tippen
   gelten beide, die spaetere gewinnt. */

@media (hover: none) {
  .card:hover, .work-card:hover, .review-card:hover, .tiktok-card:hover,
  .portrait:hover, .btn:hover, .icon-btn:hover, .filter:hover {
    transform: none;
  }
  .work-card:hover .work-img, .card:hover .card-icon { transform: none; }

  .card:active, .work-card:active, .review-card:active, .tiktok-card:active,
  .portrait:active {
    transform: scale(.985);
    border-color: var(--accent-line);
    transition-duration: .1s;
  }
  .btn:active, .icon-btn:active, .filter:active {
    transform: scale(.96);
    transition-duration: .1s;
  }
  /* Karten sind Links/Kacheln -- der graue iOS-Tap-Kasten stoert dort. */
  .card, .work-card, .review-card, .tiktok-card, .portrait, .btn, .icon-btn, .filter {
    -webkit-tap-highlight-color: transparent;
  }
}

/* ---------- Druck ---------- */

@media print {
  body::before, body::after { display: none; }
  body { background: #fff; color: #000; }
  .site-header, .site-footer, .action-bar, .mobile-menu, .cta, .theme-toggle, .toc { display: none !important; }
  .js .reveal { opacity: 1; transform: none; }
  .hero-in, .hero-visual, .hero h1 .line > span { animation: none !important; opacity: 1; transform: none; }
}

/* Eigene Videodatei im Feed (statt TikTok-Player): formatfuellend wie das
   Vorschaubild, damit der Wechsel zwischen beiden Player-Arten nicht auffaellt. */
.tiktok-slide-player video { width: 100%; height: 100%; object-fit: cover; display: block; background: #0b090f; }

/* Der Admin-Zugang steckt im ©-Zeichen im Footer: sichtbar bleibt nur das
   Zeichen selbst, der Hinweis erscheint erst beim Draufzeigen. */
.footer-admin-link { color: inherit; text-decoration: none; cursor: pointer; }
.footer-admin-link:hover, .footer-admin-link:focus-visible { color: var(--accent-ink); }

/* ---------- Glossar ----------
   Eine durchsuchbare Seite statt vieler duenner Unterseiten. Die Begriffe
   sind <details>-Elemente: aufklappbar ganz ohne JavaScript, tastaturbedienbar
   von Haus aus. glossar.js filtert zusaetzlich beim Tippen. */

.glossary-search { margin-bottom: 1rem; }

.glossary-search-field {
  position: relative;
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .2rem .9rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--color-surface);
  transition: border-color .22s, box-shadow .22s;
}
.glossary-search-field:focus-within {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.glossary-search-field svg { flex: none; width: 1.15rem; height: 1.15rem; color: var(--color-text-muted); }

.glossary-search-field input {
  flex: 1 1 auto;
  min-width: 0;
  padding: .85rem 0;
  border: 0;
  background: none;
  color: var(--color-text);
  font: inherit;
  font-size: 1rem;
}
.glossary-search-field input:focus { outline: none; }
/* Das browsereigene X der Suchfelder weg -- wir haben einen eigenen Knopf. */
.glossary-search-field input::-webkit-search-cancel-button { display: none; }

.glossary-clear {
  flex: none;
  display: grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  border: 0;
  border-radius: 50%;
  background: var(--color-surface-alt);
  color: var(--color-text-muted);
  cursor: pointer;
}
.glossary-clear:hover { color: var(--color-text); }
.glossary-clear svg { width: .95rem; height: .95rem; }

.glossary-filters { display: flex; flex-wrap: wrap; gap: .45rem; margin-bottom: 1rem; }
/* Die Filter sind hier Links (damit sie ohne JavaScript funktionieren und
   sich teilen lassen), nicht Knoepfe -- deshalb kein aria-pressed, sondern
   eine eigene Klasse fuer den aktiven Zustand. */
.glossary-filters .filter { text-decoration: none; }
.glossary-filters .filter.is-active {
  border-color: var(--color-accent);
  background: var(--accent-soft);
  color: var(--color-text);
}
.filter-count { opacity: .6; font-size: .85em; }

.glossary-alphabet {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
  margin-bottom: 1.4rem;
  padding-bottom: 1.2rem;
  border-bottom: 1px solid var(--line);
}
.glossary-alphabet a {
  display: grid;
  place-items: center;
  min-width: 2rem;
  height: 2rem;
  border-radius: var(--radius);
  color: var(--color-text-muted);
  font-weight: 600;
  font-size: .9rem;
  text-decoration: none;
}
.glossary-alphabet a:hover { background: var(--color-surface-alt); color: var(--accent-ink); }

.glossary-status { margin: 0 0 1rem; color: var(--color-text-muted); font-size: .9rem; }
.glossary-empty { color: var(--color-text-muted); }

.glossary-group { margin-bottom: 1.8rem; scroll-margin-top: 5.5rem; }

.glossary-letter {
  margin: 0 0 .6rem;
  color: var(--accent-ink);
  font-family: var(--serif);
  font-size: 1.5rem;
  font-style: italic;
}

.glossary-entries { display: grid; gap: .5rem; }

.glossary-entry {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--color-surface);
  overflow: hidden;
  /* Anker aus der A-Z-Leiste sollen nicht unter der klebenden Kopfzeile landen. */
  scroll-margin-top: 5.5rem;
}
.glossary-entry[open] { border-color: var(--accent-line); }

.glossary-entry > summary {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .85rem 1rem;
  cursor: pointer;
  list-style: none;
}
.glossary-entry > summary::-webkit-details-marker { display: none; }
.glossary-entry > summary::before {
  content: "";
  flex: none;
  width: 0;
  height: 0;
  border-left: 6px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  color: var(--color-text-muted);
  transition: transform .2s;
}
.glossary-entry[open] > summary::before { transform: rotate(90deg); }

.glossary-term { font-weight: 600; overflow-wrap: anywhere; }

.glossary-badge {
  margin-left: auto;
  flex: none;
  padding: .12rem .6rem;
  border-radius: 999px;
  background: var(--color-surface-alt);
  color: var(--color-text-muted);
  font-size: .75rem;
}

.glossary-body { padding: 0 1rem 1rem 2.1rem; }
.glossary-body p { margin: 0 0 .6rem; }
.glossary-body p:last-child { margin-bottom: 0; }
.glossary-short { color: var(--color-text); }
.glossary-long { color: var(--color-text-muted); line-height: 1.65; }
.glossary-synonyms { color: var(--color-text-muted); font-size: .85rem; font-style: italic; }

.glossary-outro { margin-top: 2rem; color: var(--color-text-muted); }

/* Nur fuer Screenreader sichtbar (Beschriftung des Suchfelds). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ============================================================
   Empfehlungen (Affiliate)
   ============================================================ */

/* Die Kategorie-Filter sind hier echte Links und funktionieren ohne
   JavaScript -- die allgemeine Regel html:not(.js) .filters {display:none}
   gilt fuer die JS-Filter der Galerie und wuerde sie zu Unrecht ausblenden. */
html:not(.js) .filters.filters-links { display: flex; }
a.filter { text-decoration: none; }
.filter.is-active { border-color: var(--accent-line); background: var(--accent-soft); color: var(--accent-ink); }

.empfehlungen-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.4rem;
}
.empfehlungen-kopf .filters { margin: 0; }

.sammelliste-link { display: inline-flex; align-items: center; gap: .5rem; text-decoration: none; }
.sammel-zaehler {
  display: inline-grid;
  place-items: center;
  min-width: 1.5rem;
  height: 1.5rem;
  padding: 0 .35rem;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-family: var(--mono);
  font-size: .72rem;
}

/* Hinweis auf Werbung. Bewusst gut sichtbar und nicht als graue Fussnote --
   die Kennzeichnung soll man lesen, bevor man klickt. */
.hinweis-box {
  padding: 1rem 1.2rem;
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-lg);
  background: var(--accent-soft);
  color: var(--color-text);
}
.hinweis-box p { margin: 0; font-size: .9rem; line-height: 1.6; }
.hinweis-box p + p { margin-top: .5rem; }
.hinweis-box-klein { margin-top: 1.5rem; padding: .8rem 1rem; }
.hinweis-box-klein p { font-size: .82rem; }
.hinweis-klein { color: var(--color-text-muted); font-size: .8rem; line-height: 1.55; }
/* Fussnote unter der Kontaktseite: da, aber nicht im Weg. */
.kontakt-fussnote { margin: 2.5rem 0 0; padding-top: 1.2rem; border-top: 1px solid var(--line-soft); max-width: 46rem; }
.kontakt-fussnote a { color: inherit; }

.produkt-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
  gap: 1rem;
}

.produkt-karte {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel);
  overflow: hidden;
  transition: transform .4s var(--ease), border-color .35s, box-shadow .4s;
}
.produkt-karte:hover { transform: translateY(-4px); border-color: var(--accent-line); box-shadow: var(--shadow-lg); }

.produkt-bild-link { display: block; }
/* Produktfotos sind Freisteller auf Weiss: contain statt cover, sonst wird
   der Rand abgeschnitten. */
.produkt-bild {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  background: #fff;
}
.produkt-bild-leer {
  display: grid;
  place-items: center;
  aspect-ratio: 1 / 1;
  background: var(--color-surface);
  color: var(--dim);
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.produkt-body { display: grid; gap: .4rem; padding: .9rem 1rem 1.1rem; }
.produkt-haendler {
  margin: 0;
  color: var(--dim);
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.produkt-titel { margin: 0; font-size: .98rem; font-weight: 600; letter-spacing: -.015em; }
.produkt-titel a { color: inherit; text-decoration: none; }
.produkt-titel a:hover { color: var(--accent-ink); }
.produkt-kurz {
  display: -webkit-box;
  margin: 0;
  color: var(--color-text-muted);
  font-size: .85rem;
  line-height: 1.55;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.produkt-preis { margin: .2rem 0 0; font-size: 1.05rem; font-weight: 600; }
.produkt-preis-gross { font-size: 1.5rem; }
.produkt-preis-hinweis {
  display: block;
  margin-top: .15rem;
  color: var(--color-text-muted);
  font-size: .74rem;
  font-weight: 400;
  line-height: 1.4;
}
.produkt-aktionen { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: .5rem; }
.produkt-aktionen-gross { margin-top: 1.5rem; gap: .7rem; }
.produkt-aktionen .btn,
.produkt-aktionen .btn-outline { text-decoration: none; }

.produkt-karte-kompakt .produkt-kurz { display: none; }
.produkt-karte-kompakt .produkt-bild,
.produkt-karte-kompakt .produkt-bild-leer { aspect-ratio: 4 / 3; }

/* Detailseite */
.produkt-detail { display: grid; gap: 1.6rem; }
.produkt-detail-bild img {
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: #fff;
  object-fit: contain;
}
.produkt-empfehlung { margin: 1.4rem 0; }
.produkt-empfehlung h2 { margin: 0 0 .5rem; font-size: 1.1rem; }
.produkt-empfehlung p { margin: 0; line-height: 1.7; }

/* Sammelliste */
.sammel-gruppe { margin-bottom: 2.4rem; }
.sammel-gruppe-kopf {
  display: flex;
  align-items: baseline;
  gap: .7rem;
  margin-bottom: .9rem;
  padding-bottom: .5rem;
  border-bottom: 1px solid var(--line);
}
.sammel-gruppe-kopf h2 { margin: 0; font-size: 1.2rem; }
.sammel-anzahl { color: var(--color-text-muted); font-family: var(--mono); font-size: .78rem; }
.sammel-gruppe-fuss { margin-top: 1.1rem; display: grid; gap: .5rem; justify-items: start; }
.sammel-position { display: grid; gap: .5rem; }
.sammel-menge { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.mengen-knopf {
  display: grid;
  place-items: center;
  width: 2.4rem;
  height: 2.4rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: inherit;
  font-size: 1.1rem;
  cursor: pointer;
}
.mengen-knopf:hover { border-color: var(--accent-line); color: var(--accent-ink); }
.mengen-wert { min-width: 1.6rem; text-align: center; font-family: var(--mono); }
.sammel-entfernen {
  margin-left: auto;
  border: 0;
  background: none;
  color: var(--color-text-muted);
  font: inherit;
  font-size: .82rem;
  text-decoration: underline;
  cursor: pointer;
}
.sammel-entfernen:hover { color: var(--accent-ink); }
.lade-hinweis { color: var(--color-text-muted); font-size: .9rem; }

@media (min-width: 760px) {
  .produkt-detail { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: 2.4rem; align-items: start; }
}

/* ============================================================
   Kundenkonto (freiwillig)
   ============================================================ */

/* Schmalere Spalte für Formularseiten -- ein Anmeldeformular über die
   volle Breite liest sich schlecht. */
.shell-schmal { max-width: 34rem; margin-inline: auto; }

.konto-link { position: relative; }
/* Kleiner Punkt am Herz zeigt: angemeldet. Kein Text, kein Name im Kopf --
   wer über die Schulter schaut, muss nicht mitlesen können, wer hier ist. */
.konto-punkt {
  position: absolute;
  top: .35rem;
  right: .35rem;
  width: .45rem;
  height: .45rem;
  border-radius: 50%;
  background: var(--accent);
}

.konto-wechsel {
  margin-top: 1.2rem;
  color: var(--color-text-muted);
  font-size: .88rem;
  text-align: center;
}
.konto-wechsel a { color: var(--accent-ink); }

.konto-aktionen { display: flex; flex-wrap: wrap; gap: .7rem; align-items: center; }
.konto-aktionen .btn,
.konto-aktionen .btn-outline { text-decoration: none; }

.design-merken { margin-top: 2rem; display: grid; gap: .6rem; justify-items: start; }

.form-erfolg {
  margin-bottom: 1.2rem;
  padding: .9rem 1.1rem;
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-lg);
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-size: .92rem;
}

/* Der Löschen-Bereich hebt sich ab: hier soll niemand aus Versehen landen. */
.form-card-gefahr { border-color: #c0392b; }
.form-card-gefahr h2 { color: #c0392b; }

.form-card + .form-card { margin-top: 1.5rem; }
.form-card h2 { margin-top: 0; font-size: 1.1rem; }

/* --- "Kurzfristig frei" (15.09.2026) ---
   Schlanke Pille direkt unter der Statuszeile, gleiche Sprache (Mono, Punkt),
   aber in der Akzentfarbe. Die ganze Pille ist der Link zur Anfrage. */
.kurzfristig {
  display: flex;
  align-items: center;
  gap: .6rem;
  width: fit-content;
  max-width: 100%;
  margin: 0 0 1.4rem;
  padding: .45rem .9rem .45rem .7rem;
  border: 1px solid color-mix(in srgb, var(--accent-ink) 55%, transparent);
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent-ink) 12%, var(--panel));
  color: var(--color-text);
  font-family: var(--mono);
  font-size: .74rem;
  letter-spacing: .03em;
  line-height: 1.35;
  text-decoration: none;
  transition: background .2s var(--ease), border-color .2s var(--ease);
}
.kurzfristig:hover,
.kurzfristig:focus-visible { background: color-mix(in srgb, var(--accent-ink) 22%, var(--panel)); border-color: var(--accent-ink); }
.kurzfristig .dot { position: relative; flex: none; width: .5rem; height: .5rem; border-radius: 50%; background: var(--accent-ink); }
.kurzfristig .dot::after { content: ""; position: absolute; inset: -.3rem; border-radius: 50%; border: 1px solid var(--accent-ink); opacity: .5; animation: pulse 2.6s ease-out infinite; }
.kurzfristig-text strong { color: var(--accent-ink); font-weight: 700; }
.kurzfristig-pfeil { flex: none; color: var(--accent-ink); transition: transform .2s var(--ease); }
.kurzfristig:hover .kurzfristig-pfeil { transform: translateX(3px); }
.status + .kurzfristig { margin-top: -.9rem; }
@media (prefers-reduced-motion: reduce) { .kurzfristig .dot::after { animation: none; } }

/* --- Gutscheinabfrage (15.09.2026) --- */
.gutschein-abfrage { display: grid; gap: 1.2rem; max-width: 34rem; }
.gutschein-form { display: grid; gap: .5rem; }
.gutschein-form label { font-weight: 600; }
.gutschein-eingabe { display: flex; flex-wrap: wrap; gap: .6rem; }
.gutschein-eingabe input {
  flex: 1 1 14rem;
  min-width: 0;
  padding: .8rem 1rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--color-text);
  font-family: var(--mono);
  font-size: 1.05rem;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.gutschein-eingabe input::placeholder { letter-spacing: .12em; opacity: .5; }
.gutschein-eingabe input:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
.gutschein-muster { font-family: var(--mono); letter-spacing: .08em; white-space: nowrap; }
.gutschein-meldung { margin: 0; padding: .8rem 1rem; border-radius: 1rem; background: color-mix(in srgb, var(--accent-ink) 12%, var(--panel)); }
.gutschein-ergebnis {
  display: grid;
  gap: .4rem;
  justify-items: start;
  padding: 1.4rem 1.5rem;
  border: 1px solid color-mix(in srgb, var(--accent-ink) 45%, var(--line));
  border-radius: 1.4rem;
  background: color-mix(in srgb, var(--accent-ink) 9%, var(--panel));
}
.gutschein-ergebnis p { margin: 0; }
.gutschein-betrag { font-family: var(--font-heading, inherit); font-size: clamp(2.6rem, 9vw, 3.6rem); font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; color: var(--accent-ink); }
.gutschein-ergebnis.ist-eingeloest .gutschein-betrag,
.gutschein-ergebnis.ist-abgelaufen .gutschein-betrag { color: var(--color-text-muted); }
.gutschein-ergebnis .btn { margin-top: .6rem; }

/* --- Gutschein online kaufen (15.09.2026) --- */
.kauf { display: grid; gap: 1.4rem; max-width: 44rem; }
.kauf-hinweis { margin: 0; padding: .8rem 1rem; border-radius: 1rem; border: 1px dashed color-mix(in srgb, currentColor 35%, transparent); }
.kauf-hinweis.ist-test { border-style: solid; background: color-mix(in srgb, #e9b45e 18%, transparent); }
.gutschein-meldung ul { margin: 0; padding-left: 1.1rem; }
.kauf-form { display: grid; gap: 1.8rem; }
.kauf-gruppe { display: grid; gap: .75rem; min-width: 0; margin: 0; padding: 0; border: 0; }
.kauf-gruppe legend { margin-bottom: .6rem; padding: 0; font-size: 1.1rem; font-weight: 700; }
.kauf-optional { font-size: .85rem; font-weight: 400; opacity: .7; }
.kauf-chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.kauf-chip { position: relative; cursor: pointer; }
.kauf-chip input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.kauf-chip span {
  display: inline-flex; align-items: center; min-height: 2.75rem; padding: .55rem 1.1rem;
  border: 1px solid color-mix(in srgb, currentColor 25%, transparent); border-radius: 999px;
  font-variant-numeric: tabular-nums; transition: background-color .15s ease, border-color .15s ease;
}
.kauf-chip input:checked + span { background: var(--accent-ink); border-color: var(--accent-ink); color: #fff; font-weight: 600; }
.kauf-chip input:focus-visible + span { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
.kauf-feld { display: grid; gap: .35rem; min-width: 0; }
.kauf-feld label { font-size: .95rem; font-weight: 600; }
.kauf-feld input {
  width: 100%; min-width: 0; padding: .75rem 1rem; border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
  border-radius: .9rem; background: var(--panel, transparent); color: inherit; font: inherit;
}
.kauf-feld input:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
/* 16rem: nebeneinander nur, wenn der Platzhalter der E-Mail ganz hineinpasst
   (neben der Vorschau ist die Formularspalte schmaler). */
.kauf-zwei { display: grid; gap: .75rem; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
.kauf-frei { max-width: 18rem; }
.kauf-falle { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.kauf-zusammenfassung {
  display: grid; gap: .8rem; padding: 1.3rem 1.4rem; border-radius: 1.4rem;
  background: var(--panel, transparent); border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
}
.kauf-zusammenfassung h2 { margin: 0; font-size: 1.2rem; }
.kauf-zusammenfassung ul { display: grid; gap: .4rem; margin: 0; padding-left: 1.1rem; }
.kauf-klein { margin: 0; font-size: .85rem; opacity: .85; }
.kauf-knopf { justify-self: start; }
.kauf-knopf[disabled] { opacity: .5; cursor: not-allowed; }
.kauf-widerruf summary { cursor: pointer; font-weight: 600; }
.kauf-widerruf-text { margin-top: .8rem; font-size: .9rem; line-height: 1.55; }

/* --- Live-Vorschau des Gutscheins (17.09.2026) ---
   Das PDF (GutscheinPdf) in klein. Alle Masse sind PDF-Millimeter: die Karte
   ist 273 x 174 mm, --mm ist einer davon in Container-Einheiten. Dadurch sieht
   die Vorschau bei 340 px genauso aus wie am grossen Bildschirm, nur kleiner.
   Farben je Motiv kommen als Variablen aus der Vorlage (--grund1, --grund2,
   --akzent, --papier), gutschein-kauf.js tauscht sie beim Motivwechsel.

   Platz: Am Handy steht die Vorschau direkt unter "Was auf dem Gutschein
   steht" -- dort, wo man gerade tippt. Ab 64rem zweispaltig: Formular links,
   Vorschau rechts klebend, so bleibt sie beim Ausfuellen im Blick. Hinweise
   und Widerrufsbelehrung behalten ihre Lesebreite von 44rem. */
.kauf-vorschau { display: grid; gap: .8rem; min-width: 0; }
.kauf-vorschau-titel { margin: 0; font-size: 1.1rem; }
.kauf-muster { display: grid; gap: .45rem; justify-items: start; }
.kauf-karte-rahmen { container-type: inline-size; filter: drop-shadow(0 .5rem 1.1rem rgba(0, 0, 0, .3)); }
.kauf-karte-formen { position: absolute; width: 0; height: 0; overflow: hidden; }
.kauf-karte {
  --mm: calc(100cqw / 273);
  --karte-serif: Georgia, "Times New Roman", serif;
  position: relative;
  aspect-ratio: 273 / 174;
  overflow: hidden;
  border-radius: calc(var(--mm) * 3);
  color: #1c1420;
  font-family: var(--font-body);
  line-height: 1.2;
  text-align: left;
  /* Kerben oben und unten an der Perforation, wie beim Ticket. Zwei Masken fuer
     je eine Haelfte -- so bleibt der Hintergrund der Seite sichtbar, egal ob
     hell, dunkel oder Jahreszeit. */
  -webkit-mask:
    radial-gradient(circle calc(var(--mm) * 3.2) at 54.58% 0, #0000 96%, #000) top / 100% 51% no-repeat,
    radial-gradient(circle calc(var(--mm) * 3.2) at 54.58% 100%, #0000 96%, #000) bottom / 100% 51% no-repeat;
  mask:
    radial-gradient(circle calc(var(--mm) * 3.2) at 54.58% 0, #0000 96%, #000) top / 100% 51% no-repeat,
    radial-gradient(circle calc(var(--mm) * 3.2) at 54.58% 100%, #0000 96%, #000) bottom / 100% 51% no-repeat;
}
.kauf-karte p { margin: 0; }

/* Links: Motivflaeche */
.kauf-karte-links {
  position: absolute; top: 0; bottom: 0; left: 0; width: calc(var(--mm) * 149); overflow: hidden;
  color: #fff;
  background: radial-gradient(circle calc(var(--mm) * 186) at 10% 10%, var(--grund1), var(--grund2));
}
/* Reiner Deckkraft-Wechsel beim Motivwechsel -- auch bei "wenig Bewegung" unbedenklich. */
.kauf-karte-deko { position: absolute; inset: 0; animation: fade-soft .35s ease both; }
.kauf-karte-form {
  position: absolute; overflow: visible;
  width: calc(var(--mm) * var(--b)); height: calc(var(--mm) * var(--h));
  fill: currentColor; stroke: currentColor;
}
.kauf-karte-logo { position: absolute; left: calc(var(--mm) * 12); top: calc(var(--mm) * 10); width: calc(var(--mm) * 58); height: auto; }
.kauf-karte-ueber {
  position: absolute; left: calc(var(--mm) * 12); top: calc(var(--mm) * 92);
  display: flex; align-items: center; height: calc(var(--mm) * 7.5); padding: 0 calc(var(--mm) * 4);
  border: max(1px, calc(var(--mm) * .35)) solid var(--akzent); border-radius: 999px;
  color: var(--akzent); font-size: calc(var(--mm) * 2.82); font-weight: 700;
  letter-spacing: calc(var(--mm) * .35); text-transform: uppercase; white-space: nowrap;
}
.kauf-karte-titel,
.kauf-karte-betrag { position: absolute; font-family: var(--karte-serif); white-space: nowrap; }
.kauf-karte-titel { left: calc(var(--mm) * 11); top: calc(var(--mm) * 104); font-size: calc(var(--mm) * 9.17); font-style: italic; }
.kauf-karte-betrag {
  left: calc(var(--mm) * 10); top: calc(var(--mm) * 116);
  font-size: calc(var(--mm) * 19.05); font-weight: 700; font-variant-numeric: tabular-nums;
}
.kauf-karte-betrag small { margin-left: .25em; font-size: .52em; color: var(--akzent); }
.kauf-karte-zusatz {
  position: absolute; left: calc(var(--mm) * 12); top: calc(var(--mm) * 161);
  font-size: calc(var(--mm) * 3); white-space: nowrap;
  color: rgba(255, 255, 255, .8);
  color: color-mix(in srgb, #fff 80%, var(--grund2));
}
.kauf-karte-perfo {
  position: absolute; z-index: 1; top: 0; bottom: 0; left: calc(var(--mm) * 148.75); width: max(1px, calc(var(--mm) * .5));
  background: repeating-linear-gradient(to bottom,
    color-mix(in srgb, var(--akzent) 55%, #d8c9d0) 0 calc(var(--mm) * 2.2),
    transparent 0 calc(var(--mm) * 3.8));
}

/* Rechts: Papier */
.kauf-karte-rechts { position: absolute; top: 0; right: 0; bottom: 0; width: calc(var(--mm) * 124); background: var(--papier); }
.kauf-karte-oben { position: absolute; left: calc(var(--mm) * 13); top: calc(var(--mm) * 12); width: calc(var(--mm) * 99); }
/* Wie im PDF: der Gruss beginnt bei 52 mm -- oder tiefer, wenn lange Namen umbrechen. */
.kauf-karte-namen { min-height: calc(var(--mm) * 36); }
.kauf-karte-zeile {
  display: flex; flex-direction: column; min-height: calc(var(--mm) * 9.9); margin-bottom: calc(var(--mm) * 4.1);
  border-bottom: max(1px, calc(var(--mm) * .3)) solid #decfd6;
}
.kauf-karte-etikett {
  display: block; margin-top: calc(var(--mm) * .8);
  font-size: calc(var(--mm) * 2.29); line-height: 1.3; letter-spacing: calc(var(--mm) * .35);
  text-transform: uppercase; color: #8d7383;
}
.kauf-karte-wert { min-height: 1.15em; font-family: var(--karte-serif); font-size: calc(var(--mm) * 4.94); line-height: 1.15; overflow-wrap: anywhere; }
.kauf-karte .kauf-karte-gruss {
  box-sizing: border-box; min-height: calc(var(--mm) * 20);
  margin-top: calc(var(--mm) * 4);
  padding: calc(var(--mm) * 3) calc(var(--mm) * 3) calc(var(--mm) * 3) calc(var(--mm) * 3.9);
  border-left: calc(var(--mm) * 1.1) solid var(--akzent);
  background: color-mix(in srgb, var(--akzent) 12%, var(--papier));
  color: #2a1622; font-family: var(--karte-serif); font-style: italic;
  font-size: calc(var(--mm) * 4.23); line-height: 1.165; overflow-wrap: anywhere;
}
.kauf-karte-ticket {
  position: absolute; left: calc(var(--mm) * 13); top: calc(var(--mm) * 118);
  box-sizing: border-box; width: calc(var(--mm) * 99); height: calc(var(--mm) * 20);
  display: flex; justify-content: space-between; align-items: flex-start; gap: calc(var(--mm) * 3);
  padding: calc(var(--mm) * 3.5) calc(var(--mm) * 5) 0;
  border: max(1px, calc(var(--mm) * .45)) dashed color-mix(in srgb, var(--akzent) 75%, #9b8390);
  border-radius: calc(var(--mm) * 3);
}
.kauf-karte-codefeld { min-width: 0; }
.kauf-karte-codefeld .kauf-karte-etikett { margin-top: 0; }
.kauf-karte-code { display: block; margin-top: calc(var(--mm) * 1.2); font-size: calc(var(--mm) * 3.3); font-weight: 600; color: #6d5a65; white-space: nowrap; }
.kauf-karte-gueltig { flex: none; text-align: right; font-size: calc(var(--mm) * 2.65); line-height: 1.3; color: #6d5a65; }
.kauf-karte-gueltig strong { display: block; font-size: calc(var(--mm) * 3.53); color: #2a1622; }
.kauf-karte-fuss {
  position: absolute; left: calc(var(--mm) * 13); top: calc(var(--mm) * 152); width: calc(var(--mm) * 99);
  font-size: calc(var(--mm) * 2.65); line-height: 1.3; color: #6d5a65;
}

/* Sehr alte Browser ohne Container-Einheiten: feste Groesse statt zerfallener Karte. */
@supports not (container-type: inline-size) {
  .kauf-karte-rahmen { max-width: 355px; }
  .kauf-karte { --mm: 1.3px; }
}

@media (min-width: 64rem) {
  .kauf { max-width: var(--shell); }
  .kauf > :not(.kauf-form) { max-width: 44rem; }
  .kauf-form { grid-template-columns: minmax(0, 1fr) minmax(0, 25rem); column-gap: clamp(2rem, 4vw, 3.5rem); align-items: start; }
  .kauf-form > * { grid-column: 1; }
  /* Fuenf Bloecke links (drei Gruppen davor, "Deine Angaben", Zusammenfassung). */
  .kauf-vorschau { grid-column: 2; grid-row: 1 / span 5; position: sticky; top: 6rem; }
}

/* --- Balken der Uebungsseite (16.09.2026) ---
   Bewusst in Warnfarben und ausserhalb der Marke: der Balken soll sichtbar
   nicht zur Seite gehoeren. Feste Farbwerte statt Tokens, damit ihn weder das
   helle Schema noch eine Jahreszeit umfaerbt -- ein dezenter Hinweis ist hier
   genau das Falsche.
   Nicht fixiert: er steht vor dem Seitenkopf in der normalen Reihenfolge und
   scrollt mit weg. Am Handy zaehlt jede Zeile Hoehe, und wer einmal gelesen
   hat, wo er ist, weiss es. */
.uebung-balken {
  margin: 0;
  padding: .55rem 1rem;
  background: repeating-linear-gradient(135deg, #ffd166 0 14px, #f4bb3c 14px 28px);
  color: #1b1206;
  border-bottom: 2px solid #1b1206;
  font-family: var(--font-body);
  font-size: .88rem;
  font-weight: 700;
  line-height: 1.35;
  text-align: center;
}
@media (max-width: 600px) {
  .uebung-balken { padding: .5rem .7rem; font-size: .8rem; }
}

/* --- Marken-Kachel statt fehlendem Titelbild im Blog (16.09.2026) ---
   Vorher stand in der Blogliste ein grauer Kasten mit Bild-Symbol: er sah aus
   wie ein Ladefehler. .work-placeholder bleibt deshalb unveraendert -- den
   nutzen auch die Galerie und das Kundenkonto -- und der Blog bekommt hier
   eine eigene Kachel im Markenbild.

   Sie bleibt in BEIDEN Farbschemata dunkel (--ink-dark), wie der TikTok-Feed:
   auf dem hellen Schema muesste sonst jede der vier Farbstimmungen einzeln
   nachgemessen werden, damit die Schrift lesbar bleibt. */
.blog-kachel {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: .8rem;
  aspect-ratio: 4 / 5;
  padding: 1.15rem 1.2rem 1.3rem;
  overflow: hidden;
  background:
    radial-gradient(18rem 15rem at 88% -12%, var(--kachel-a), transparent 68%),
    radial-gradient(16rem 16rem at -8% 110%, var(--kachel-b), transparent 66%),
    var(--ink-dark);
  color: #f7f2f8;
}
/* Vier Stimmungen, gewuerfelt aus dem Slug (_blog_platzhalter.twig). */
.blog-kachel-1 { --kachel-a: rgba(230, 25, 122, .85); --kachel-b: rgba(124, 77, 255, .55); }
.blog-kachel-2 { --kachel-a: rgba(124, 77, 255, .75); --kachel-b: rgba(230, 25, 122, .6); }
.blog-kachel-3 { --kachel-a: rgba(255, 90, 165, .7);  --kachel-b: rgba(124, 77, 255, .3); }
.blog-kachel-4 { --kachel-a: rgba(var(--season-rgb), .8); --kachel-b: rgba(230, 25, 122, .5); }

.blog-kachel > span { position: relative; z-index: 1; }

.blog-kachel-marke {
  color: rgba(247, 242, 248, .72);
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .22em;
  text-transform: uppercase;
}
.blog-kachel-titel {
  display: -webkit-box;
  font-family: var(--serif);
  font-size: clamp(1.05rem, 3.2vw, 1.45rem);
  line-height: 1.25;
  letter-spacing: -.01em;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Ein langsam wandernder Glanzstreifen -- dieselbe Sprache wie die uebrigen
   Glanzlichter. Nur transform, also ohne Layout-Neuberechnung. */
.blog-kachel::after {
  content: "";
  position: absolute;
  inset: -40%;
  z-index: 0;
  background: linear-gradient(115deg, transparent 42%, rgba(255, 255, 255, .12) 50%, transparent 58%);
  animation: kachel-glanz 11s var(--ease) infinite;
  pointer-events: none;
}
@keyframes kachel-glanz {
  0%, 100% { transform: translate3d(-22%, 0, 0); }
  50%      { transform: translate3d(22%, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .blog-kachel::after { animation: none; }
}

/* --- Bilderblock im Blogbeitrag (16.09.2026, Migration 058) ---
   Eigener Block unter dem Text: im Fliesstext sind Bilder nicht moeglich,
   weil der HtmlSanitizer <img> entfernt -- und das soll er auch. */
.blog-bilder { display: grid; gap: 1.1rem; margin: 2.6rem 0 0; }
.blog-bilder > h2 { margin: 0; font-size: clamp(1.2rem, 4vw, 1.55rem); }
.blog-bilder figure { margin: 0; }
.blog-bilder figcaption {
  margin-top: .5rem;
  color: var(--color-text-muted);
  font-size: .88rem;
  line-height: 1.5;
}
.blog-bilder img {
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}

/* Verlauf: nummerierte Schritte von 0 bis fertig. Gleicher Ausschnitt fuer
   alle Schritte (4:5), sonst huepfen die Bilder in der Reihe. */
.blog-verlauf {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: 1.3rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.blog-verlauf-schritt { position: relative; display: grid; align-content: start; }
.blog-verlauf-bild { aspect-ratio: 4 / 5; object-fit: cover; }
.blog-verlauf-nummer {
  position: absolute;
  top: .85rem;
  left: .85rem;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--on-accent);
  font-family: var(--mono);
  font-size: .85rem;
  font-weight: 700;
}
.blog-verlauf-text {
  margin: .5rem 0 0;
  color: var(--color-text-muted);
  font-size: .88rem;
  line-height: 1.5;
}

/* Raster: freie Groessen, deshalb oben buendig statt gestreckt. */
.blog-raster {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  align-items: start;
  gap: 1.1rem;
}

/* Vorher / Nachher: beide Bilder im selben Ausschnitt, sonst vergleicht man
   Bildformate statt Naegel. */
.blog-vergleich {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: 1.1rem;
}
.blog-vergleich img { aspect-ratio: 4 / 5; object-fit: cover; }
.blog-vergleich-marke {
  display: inline-block;
  margin-right: .35rem;
  color: var(--accent-ink);
  font-family: var(--mono);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
}

/* "Link kopiert" -- ohne Teilen-Funktion des Browsers (z. B. Firefox am
   Laptop) sah man vorher gar nichts, der Link lag still in der Zwischenablage. */
.kopiert-hinweis {
  position: fixed; left: 50%; bottom: calc(5.5rem + env(safe-area-inset-bottom, 0px)); z-index: 60;
  transform: translate(-50%, .5rem); opacity: 0;
  padding: .55rem 1rem; border-radius: 999px;
  background: rgba(11, 9, 15, .9); color: #fff; font-size: .85rem; font-weight: 600;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .25);
  transition: opacity .2s, transform .2s;
  pointer-events: none;
}
.kopiert-hinweis.ist-sichtbar { opacity: 1; transform: translate(-50%, 0); }
@media (prefers-reduced-motion: reduce) { .kopiert-hinweis { transition: none; } }

/* --- Profile auf /videos und Plattform-Knoepfe in der Kachel (18.09.2026) ---
   Die Profile als runde Knoepfe wie im Player, nur in Pink -- vorher zwei
   grosse Umriss-Knoepfe mit langem Text, die wie ein Fremdkoerper neben dem
   Feed wirkten. In der laufenden Startseiten-Kachel dieselben Knoepfe wie im
   Feed, damit man auch dort zum Video auf TikTok oder YouTube kommt. */

.profil-knoepfe {
  display: flex;
  flex-wrap: wrap;
  gap: 1.3rem;
  margin: 1.5rem 0 0;
  padding: 0;
  list-style: none;
}

.profil-knopf {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: .45rem;
  color: var(--color-text);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-decoration: none;
}

.profil-knopf-rund {
  display: grid;
  place-items: center;
  width: 3.4rem;
  height: 3.4rem;
  border-radius: 50%;
  background: var(--color-accent);
  color: #fff;
  box-shadow: 0 8px 24px color-mix(in srgb, var(--color-accent) 32%, transparent);
  transition: transform .2s var(--ease), box-shadow .2s var(--ease);
}

.profil-knopf-rund .icon { width: 1.45rem; height: 1.45rem; }

.profil-knopf:hover .profil-knopf-rund {
  transform: translateY(-2px);
  box-shadow: 0 12px 30px color-mix(in srgb, var(--color-accent) 45%, transparent);
}

.profil-knopf:focus-visible { outline: none; }
.profil-knopf:focus-visible .profil-knopf-rund { outline: 2px solid var(--fokus-ring); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .profil-knopf-rund { transition: none; }
  .profil-knopf:hover .profil-knopf-rund { transform: none; }
}

/* Oben links im laufenden Video, gegenueber dem Ton-Knopf. Vor dem Abspielen
   unsichtbar UND nicht per Tab erreichbar (visibility). */
.tiktok-card-plattformen {
  --fokus-ring: var(--fokus-ring-auf-dunkel);
  position: absolute;
  top: .5rem;
  left: .5rem;
  z-index: 2;
  display: flex;
  gap: .4rem;
  visibility: hidden;
  opacity: 0;
  transition: opacity .25s, visibility 0s .25s;
}

.tiktok-card.is-loaded .tiktok-card-plattformen {
  visibility: visible;
  opacity: 1;
  transition: opacity .25s;
}

.tiktok-card-plattform {
  display: grid;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 50%;
  background: rgba(11, 9, 15, .42);
  color: #fff;
  -webkit-tap-highlight-color: transparent;
}

.tiktok-card-plattform:hover { background: var(--color-accent); border-color: transparent; }
.tiktok-card-plattform .icon { width: 1.15rem; height: 1.15rem; }
