@charset "UTF-8";
/* ============================================================
   GS Fitness · components.css
   Benannte Komponenten (2+ Seiten wiederverwendet). Alle Werte aus
   Tokens. Register mit Erkennungssignal und Markup-Skelett: CLAUDE.md
   ============================================================ */

/* ---------- Skip-Link ----------
   Versteckt ueber einen Offset, der groesser ist als die eigene Hoehe
   (Padding + Zeilenbox); rem-basiert, damit er auch bei 400 % Zoom traegt. */
.gsSkip{position:absolute;left:var(--s-2);top:calc(var(--s-20) * -1);z-index:var(--z-skip);
  display:flex;align-items:center;min-height:var(--size-control);
  background:var(--color-brand);color:var(--color-text-invert);padding:var(--s-3) var(--s-4);
  line-height:var(--leading-tight);
  border-radius:0 0 var(--radius-sm) var(--radius-sm);text-decoration:none;
  font-weight:var(--weight-semi);transition:top var(--duration-fast)}
.gsSkip:focus{top:0}

/* Fokus auf dunklen/kraeftigen Flaechen invertiert */
.gsSubHero :focus-visible,
.gsCtaBand :focus-visible,
.gsFooter :focus-visible,
.u-bg-dark :focus-visible,
.u-bg-action :focus-visible,
.u-bg-grad-brand :focus-visible{outline-color:var(--color-focus-invert)}

/* ---------- Inline-Textlink: persistent unterstrichen ---------- */
a.gsInline{color:var(--color-accent);text-decoration:underline;text-underline-offset:3px;
  text-decoration-thickness:2px}
a.gsInline:hover{color:var(--color-accent-strong)}

/* ---------- Maskierte E-Mail: Vor-JS-Fallback „user∂domain“ ---------- */
.gsMail{overflow-wrap:anywhere}

/* Scroll-Sperre bei offenem Navigations-Panel */
.gsNoScroll{overflow:hidden}

/* ---------- Seitenrahmen ---------- */
.gsShell{position:relative;overflow-x:clip;background:var(--color-surface);
  max-width:var(--width-shell);margin:0 auto;padding-top:var(--space-header)}
.no-js .gsShell{padding-top:0}

/* ============================================================
   Navigation — ein Markup, zwei Darstellungen
   Basis (auch ohne JS): vollstaendige, sichtbare verschachtelte Liste
   ============================================================ */
.gsHeader{position:relative;background:var(--color-surface-glass);
  border-bottom:var(--border-hair) solid var(--color-line)}
.js .gsHeader{position:fixed;top:0;left:0;right:0;z-index:var(--z-nav)}
/* Glas-Effekt bewusst auf einem Pseudo-Element: ein backdrop-filter am
   Header selbst wuerde ihn zum Containing Block fuer position:fixed machen –
   das mobile Navigations-Panel waere dann auf die Header-Hoehe zusammengefallen. */
.js .gsHeader::before{content:"";position:absolute;inset:0;z-index:-1;
  backdrop-filter:blur(10px);pointer-events:none}
.gsNav{max-width:var(--width-nav);margin:0 auto;display:flex;flex-wrap:wrap;
  align-items:center;gap:var(--s-3);padding:var(--s-3) var(--space-gutter);
  transition:padding var(--duration-slow) var(--ease-base)}
.gsBrand{display:flex;align-items:center;text-decoration:none;flex:none;margin-right:auto}
.gsBrandImg{display:block;height:var(--size-logo);width:auto;flex:none;
  transition:height var(--duration-slow) var(--ease-base)}

.gsNavToggle{display:none}
.js .gsNavToggle{display:grid;place-items:center;width:var(--size-control);
  height:var(--size-control);min-height:var(--size-control);border-radius:var(--radius-md);
  border:var(--border-hair) solid var(--color-line-mid);background:var(--color-surface-alt);
  color:var(--color-text);flex:none;cursor:pointer;padding:0}
.gsNavToggle .gsIconClose{display:none}
.gsNavToggle[aria-expanded="true"] .gsIconOpen{display:none}
.gsNavToggle[aria-expanded="true"] .gsIconClose{display:block}

.gsNavQuick{display:none}
.js .gsNavQuick{display:grid;place-items:center;width:var(--size-control);
  height:var(--size-control);border-radius:var(--radius-pill);background:var(--color-action);
  color:var(--color-text-invert);flex:none;text-decoration:none;
  transition:background-color var(--duration-base) var(--ease-base),color var(--duration-base) var(--ease-base)}
.js .gsNavQuick:hover{background:var(--color-surface-alt);color:var(--color-action);
  box-shadow:inset 0 0 0 var(--border-thick) var(--color-action)}

.gsNavPanel{width:100%}
.gsNavList{list-style:none;margin:0;padding:0}
.gsNavList > li{display:block}
.gsNavLink,.gsNavTrigger{display:flex;align-items:center;gap:var(--s-1);width:100%;
  min-height:var(--size-control);padding:0 var(--s-3);font:inherit;font-size:var(--text-base);
  font-weight:var(--weight-medium);color:var(--color-text);text-decoration:none;
  background:none;border:0;border-radius:var(--radius-md);cursor:pointer;
  transition:color var(--duration-base) var(--ease-base),background-color var(--duration-base) var(--ease-base)}
.gsNavTrigger{justify-content:space-between}
.gsNavLink:hover,.gsNavTrigger:hover{color:var(--color-brand)}
.gsNavLink[aria-current="page"]{color:var(--color-brand)}
.gsNavTrigger[data-active="true"]{color:var(--color-brand)}
.gsNavSubList{list-style:none;margin:0;padding:0}
.gsNavSubLink{display:flex;align-items:center;gap:var(--s-2);min-height:var(--size-control);
  padding:0 var(--s-4);font-size:var(--text-base);font-weight:var(--weight-medium);
  color:var(--color-text-muted);text-decoration:none;border-left:var(--border-thick) solid var(--color-accent-soft);
  border-radius:0 var(--radius-sm) var(--radius-sm) 0;
  transition:background-color var(--duration-base) var(--ease-base),color var(--duration-base) var(--ease-base)}
.gsNavSubLink:hover{background:var(--color-accent-soft);color:var(--color-brand-dark)}
.gsNavSubLink[aria-current="page"]{background:var(--color-accent-soft);color:var(--color-brand-dark);
  font-weight:var(--weight-bold)}
.gsNavSubIcon{flex:none;color:var(--color-accent)}
.gsCh{flex:none;transition:transform var(--duration-fast) var(--ease-base)}
.gsNavTrigger[aria-expanded="true"] .gsCh{transform:rotate(180deg)}
/* Ohne JS ist die Unterebene ausgeklappt – der Trigger ist dann reine
   Beschriftung, kein Bedienelement. */
.no-js .gsNavTrigger{cursor:default}
.no-js .gsCh{display:none}
.gsNavCtas{list-style:none;margin:0;padding:var(--s-4) var(--s-3) 0;
  display:flex;flex-direction:column;gap:var(--s-3)}
.gsNavCta{display:flex}
.gsNavCta > a{flex:1}
/* Sentinel fuer den kompakten Header (nur Messpunkt) */
.gsSentinel{position:absolute;top:0;left:0;width:1px;height:var(--s-8);pointer-events:none}
/* Ebenen-Kopf des Drill-Down (per JS eingefuegt) */
.gsNavBack,.gsNavLevel{display:none}

/* ---------- Mobil (Default-Zustand, <= 1024px) mit JS: Drill-Down ---------- */
@media (max-width:1024px){
  .js .gsNavPanel{position:fixed;top:var(--space-header);left:0;right:0;bottom:0;
    z-index:var(--z-overlay);background:var(--color-surface);overflow:hidden;display:none}
  .js .gsNavPanel.is-open{display:block}
  /* Panel = Liste (scrollt) + CTA-Gruppe (bleibt am unteren Browserrand) */
  .js .gsNavStack{position:absolute;inset:0;display:flex;flex-direction:column;overflow:hidden}
  /* overflow-x:hidden ist Pflicht, nicht Kosmetik: die geschlossene Unterebene
     steht per translateX(100%) rechts daneben und wuerde als horizontaler
     Scrollbereich zaehlen. Ebenso die 8px Innenabstand, in die das absolut
     positionierte Panel hineinragt. */
  .js .gsNavStack > .gsNavList{position:relative;flex:1;min-height:0;
    overflow-y:auto;overflow-x:hidden;
    padding:var(--s-2) var(--s-2) var(--s-4)}
  /* Waehrend eine Unterebene offen ist, scrollt die Ausgangsebene nicht mit */
  .js .gsNavPanel[data-level="1"] .gsNavStack > .gsNavList{overflow:hidden}
  .js .gsNavLink,.js .gsNavTrigger{min-height:var(--s-13);font-family:var(--font-display);
    font-weight:var(--weight-semi);font-size:var(--text-md)}
  /* Unterebene deckt genau den Listenbereich ab – die CTA-Gruppe bleibt sichtbar */
  .js .gsNavSub{position:absolute;inset:0;
    z-index:var(--z-raised);background:var(--color-surface);
    overflow-y:auto;overflow-x:hidden;padding:var(--s-2) 0 var(--s-4);visibility:hidden;
    transform:translateX(100%);transition:transform var(--duration-fast) var(--ease-base),visibility var(--duration-fast)}
  .js .gsNavTrigger[aria-expanded="true"] + .gsNavSub{visibility:visible;transform:none}
  .js .gsNavBack{display:flex;align-items:center;gap:var(--s-2);width:100%;
    min-height:var(--size-control);padding:0 var(--s-3);margin:0 0 var(--s-2);
    font:inherit;font-family:var(--font-display);font-weight:var(--weight-semi);
    font-size:var(--text-base);color:var(--color-brand);background:none;border:0;
    border-radius:var(--radius-md);cursor:pointer}
  .js .gsNavBack:hover{background:var(--color-accent-soft);color:var(--color-brand-dark)}
  .js .gsNavLevel{display:block;padding:0 var(--s-3) var(--s-2);font-family:var(--font-display);
    font-weight:var(--weight-bold);font-size:var(--text-md);color:var(--color-text)}
  .js .gsNavSubLink{min-height:var(--s-12);font-size:var(--text-base)}
  /* CTA-Gruppe: volle Panelbreite, uebereinander, per Haarlinie abgesetzt.
     env() deckt die Geraete-Sicherheitszone (Home-Bar) ab. */
  .js .gsNavCtas{flex:none;background:var(--color-surface);
    border-top:var(--border-hair) solid var(--color-line);
    padding:var(--s-3) var(--s-3) calc(var(--s-3) + env(safe-area-inset-bottom, 0px))}
}
@media (max-width:1024px) and (prefers-reduced-motion:no-preference){
  .js .gsNavPanel.is-open{animation:gsFade var(--duration-fast) var(--ease-base) both}
}
@media (max-width:1024px) and (prefers-reduced-motion:reduce){
  .js .gsNavSub{transition:none}
}

/* ---------- Desktop (ab 1025px) mit JS: Disclosure-Dropdowns ---------- */
@media (min-width:1025px){
  .js .gsNav{padding:var(--s-5) var(--space-gutter);flex-wrap:nowrap;gap:var(--s-8)}
  .js .gsNavToggle,.js .gsNavQuick{display:none}
  .js .gsNavPanel{width:auto}
  .js .gsNavStack{display:flex;align-items:center;gap:var(--s-5)}
  .js .gsNavStack > .gsNavList{display:flex;align-items:center;gap:var(--s-5)}
  .js .gsNavList > li{display:flex;align-items:center;position:relative}
  .js .gsNavLink,.js .gsNavTrigger{padding:0;white-space:nowrap;border-radius:0}
  .js .gsNavLink:hover,.js .gsNavTrigger:hover{background:none}
  .js .gsNavSub{position:absolute;top:100%;left:0;padding-top:var(--s-4);
    opacity:0;visibility:hidden;z-index:var(--z-menu);
    transition:opacity var(--duration-fast) var(--ease-base)}
  .js .gsNavSubList{min-width:15rem;background:var(--color-surface-alt);
    border:var(--border-hair) solid var(--color-line);border-radius:var(--radius-lg);
    box-shadow:var(--shadow-menu);padding:var(--s-2);transform:translateY(var(--s-1));
    transition:transform var(--duration-fast) var(--ease-base)}
  .js .gsNavGroup:hover .gsNavSub,
  .js .gsNavTrigger[aria-expanded="true"] + .gsNavSub{opacity:1;visibility:visible}
  .js .gsNavGroup:hover .gsNavSubList,
  .js .gsNavTrigger[aria-expanded="true"] + .gsNavSub .gsNavSubList{transform:none}
  .js .gsNavGroup:hover .gsCh{transform:rotate(180deg)}
  .js .gsNavSubLink{border-left:0;border-radius:var(--radius-sm);padding:var(--s-3) var(--s-4);
    white-space:nowrap;color:var(--color-text)}
  .js .gsNavCtas{flex-direction:row;padding:0;border-top:0;background:none}
  /* Der Telefon-CTA gehoert nur ins mobile Panel. */
  .js .gsNavCtas > li.gsNavCta--call{display:none}
  .js .gsHeader.is-compact{--size-logo:var(--s-15)}
  .js .gsHeader.is-compact .gsNav{padding-top:var(--s-3);padding-bottom:var(--s-3)}
}
@media (min-width:1025px) and (max-width:1240px){
  .js .gsNav{gap:var(--s-4)}
  .js .gsNavStack > .gsNavList{gap:var(--s-3)}
  .js .gsHeader{--size-logo:var(--s-15)}
}

/* ---------- Buttons ---------- */
.gsBtn{display:inline-flex;align-items:center;justify-content:center;gap:var(--s-2);
  min-height:var(--size-control);padding:var(--s-3) var(--s-5);border-radius:var(--radius-lg);
  font-size:var(--text-base);font-weight:var(--weight-semi);text-decoration:none;cursor:pointer}
.gsBtnPrimary{min-height:var(--size-control);background:var(--color-action);color:var(--color-text-invert);
  transition:background-color var(--duration-base) var(--ease-base),color var(--duration-base) var(--ease-base),
    box-shadow var(--duration-base) var(--ease-base),transform var(--duration-fast)}
.gsBtnPrimary:hover{background:var(--color-surface-alt);color:var(--color-action);
  box-shadow:inset 0 0 0 var(--border-thick) var(--color-action);transform:translateY(-1px)}
.gsBtnWhite{min-height:var(--size-control);background:var(--color-surface-alt);color:var(--color-accent);
  transition:transform var(--duration-fast),background var(--duration-fast),border-color var(--duration-fast)}
.gsBtnWhite:hover{transform:translateY(-2px)}
.gsBtnOutline{min-height:var(--size-control);background:var(--color-surface-alt);color:var(--color-accent);
  border:var(--border-thick) solid var(--color-accent-soft);
  transition:border-color var(--duration-fast),background var(--duration-fast)}
.gsBtnOutline:hover{border-color:var(--color-brand-dark);background:var(--color-accent-soft);color:var(--color-accent-strong)}
.gsBtnGhostLight{min-height:var(--size-control);color:var(--color-text-invert);border:var(--border-thick) solid var(--color-line-invert-strong);
  transition:background var(--duration-fast),border-color var(--duration-fast)}
.gsBtnGhostLight:hover{background:var(--color-surface-invert-soft);border-color:var(--color-text-invert)}

/* ---------- Hover-Anhebung wiederkehrender Karten ---------- */
.gsLift{transition:transform var(--duration-fast),box-shadow var(--duration-fast)}
.gsLift:hover,.gsLift:focus-within{transform:translateY(-3px);box-shadow:var(--shadow-card-md)}
.gsHeroRating{transition:transform var(--duration-fast),box-shadow var(--duration-fast)}
.gsHeroRating:hover,.gsHeroRating:focus-visible{transform:translateY(-3px);box-shadow:var(--shadow-rating)}
.gsSocial{transition:background-color var(--duration-base) var(--ease-base),transform var(--duration-fast)}
.gsSocial:hover,.gsSocial:focus-visible{background:var(--color-brand);transform:translateY(-2px)}

/* ---------- Bewegung: ein Entrance-Muster projektweit ---------- */
@keyframes gsFade{from{opacity:0}to{opacity:1}}
@keyframes gsRevUp{from{opacity:0;transform:translateY(30px)}to{opacity:1;transform:none}}
@keyframes gsFloatA{0%,100%{transform:translate(0,0) scale(1)}50%{transform:translate(26px,-30px) scale(1.06)}}
@keyframes gsFloatB{0%,100%{transform:translate(0,0) scale(1)}50%{transform:translate(-30px,24px) scale(1.1)}}
@keyframes gsDrift{0%,100%{transform:translate(0,0) rotate(0deg)}50%{transform:translate(16px,16px) rotate(5deg)}}
@keyframes gsMorph{0%,100%{border-radius:42% 58% 63% 37%/45% 38% 62% 55%}25%{border-radius:58% 42% 38% 62%/52% 61% 39% 48%}50%{border-radius:36% 64% 56% 44%/61% 44% 56% 39%}75%{border-radius:54% 46% 48% 52%/39% 53% 47% 61%}}
@keyframes gsFaqDown{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
/* Ausgangszustand ist sichtbar – nie opacity:0 als CSS-Default */
.gsReveal{opacity:1}
.gsBlob{border-radius:var(--radius-blob-a)}
@media (prefers-reduced-motion:no-preference){
  .gsReveal{animation:gsRevUp linear both;animation-timeline:view();animation-range:entry 2% cover 20%}
  .gsBlob{animation:gsFloatA 17s ease-in-out infinite,gsMorph 15s ease-in-out infinite}
  .gsBlob.b{animation:gsFloatB 20s ease-in-out infinite,gsMorph 18s ease-in-out infinite -4s}
  .gsBlob.c{animation:gsDrift 23s ease-in-out infinite,gsMorph 21s ease-in-out infinite -7s}
  details[open] .gsFaqA{animation:gsFaqDown var(--duration-slow) var(--ease-base) both}
}

/* ---------- Geschwungene Section-Uebergaenge (nur im Desktop-Rahmen) ---------- */
@media (min-width:1025px){
  .gsWaveTop{clip-path:url(#gsWaveT);margin-top:calc(var(--s-14) * -1)}
  .gsWaveTopBot{clip-path:url(#gsWaveTB);margin-top:calc(var(--s-14) * -1)}
}

/* ---------- Startseiten-Hero ---------- */
.gsHero{display:block;min-height:auto;padding:0}
.gsHeroMosaic{height:var(--height-hero-img);bottom:auto;
  display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;
  gap:var(--border-hair);background:var(--color-line-mid)}
.gsHeroTile{display:block;position:relative;overflow:hidden;min-width:0;min-height:0}
.gsHeroImg{height:100%}
/* Rundes Markenzeichen auf dem Kreuzpunkt der vier Kacheln – nur im mobilen Rahmen.
   Liegt bewusst auf --z-content, also ueber dem Scrim (--z-raised), damit es nicht
   angedunkelt wird; die Karte folgt im Markup und bleibt damit obenauf. Zentriert wird
   gegen die Mosaik-Box selbst (absolut, also ausserhalb des Grid-Flusses – keine
   fuenfte Kachel). */
.gsHeroBadge{top:50%;left:50%;transform:translate(-50%,-50%);width:var(--size-hero-badge)}
.gsHeroOverlay{height:var(--height-hero-img);bottom:auto;background:var(--gradient-scrim-mobile)}
.gsHeroInner{padding:0}
.gsHeroCard{max-width:none;display:flex;flex-direction:column;
  margin:calc(var(--height-hero-img) - var(--s-18)) var(--space-gutter) 0;
  background:var(--color-surface);border-radius:var(--radius-3xl);
  border-top:var(--border-accent) solid var(--color-action);
  padding:var(--s-6) var(--s-4) var(--s-7);box-shadow:none}
.gsHeroTitle{hyphens:none;overflow-wrap:normal;word-break:normal}
.gsHeroText{max-width:var(--measure)}
.gsHeroCtas{flex-direction:column;align-items:stretch;gap:var(--s-3)}
.gsHeroCtas > a{width:100%;justify-content:center;min-height:var(--s-13)}
.gsHeroRating{align-self:center}
.gsHeroWave{display:none}
@media (min-width:1025px){
  .gsHero{display:flex;align-items:center;min-height:var(--height-hero)}
  .gsHeroMosaic{inset:0;height:auto}
  .gsHeroBadge{display:none}
  .gsHeroOverlay{display:none}
  .gsHeroInner{padding:var(--s-12) var(--space-gutter)}
  /* Mosaik-Kacheln ruhen unscharf und werden einzeln beim Hover scharf. Die leichte
     Skalierung verdeckt die weiche Kante, die `blur()` am Elementrand erzeugt.
     Damit der Hover die Kacheln erreicht, sind die darueberliegenden dekorativen
     Ebenen fuer Zeiger durchlaessig – die Karte selbst nimmt Klicks wieder an. */
  .gsHeroInner{pointer-events:none}
  .gsHeroCard{pointer-events:auto}
  .gsHeroWave{pointer-events:none}
  .gsHeroTile .gsHeroImg{filter:blur(3px);transform:scale(1.04)}
  .gsHeroTile:hover .gsHeroImg,
  .gsHeroTile:focus-within .gsHeroImg{filter:blur(0);transform:scale(1)}
  .gsHeroCard{max-width:var(--width-hero-card);display:block;margin:0 auto;
    background:var(--color-surface-glass-strong);border-radius:var(--radius-4xl);
    padding:var(--s-12);box-shadow:var(--shadow-card-lg)}
  .gsHeroCtas{flex-direction:row;align-items:center;gap:var(--s-4);flex-wrap:wrap}
  .gsHeroCtas > a{width:auto}
  .gsHeroRating{align-self:auto}
  .gsHeroWave{display:block;color:var(--color-surface-alt)}
}
/* Der Schaerfewechsel wird nur animiert, wenn Bewegung erwuenscht ist; der unscharfe
   Ruhezustand und das scharfe Hover-Ergebnis gelten unabhaengig davon. */
@media (min-width:1025px) and (prefers-reduced-motion:no-preference){
  .gsHeroTile .gsHeroImg{transition:filter var(--duration-slow) var(--ease-base),
    transform var(--duration-slow) var(--ease-base)}
}
@supports (animation-timeline:scroll()){
  @media (min-width:1025px) and (prefers-reduced-motion:no-preference){
    .gsHeroCard{animation:gsHeroOut linear both;animation-timeline:scroll(root block);
      animation-range:0 80vh;will-change:opacity}
  }
}
@keyframes gsHeroOut{to{opacity:0}}

/* ---------- Section-Gerueste ---------- */
.gsSec{position:relative;padding:var(--space-section) var(--space-gutter)}
.gsSec--tight{position:relative;padding:var(--space-section-tight) var(--space-gutter)}
.gsWrap{max-width:var(--width-page);margin:0 auto}
.gsWrap--narrow{max-width:var(--width-narrow);margin:0 auto}
.gsIntro{max-width:var(--width-intro);margin:0 0 var(--s-12)}
/* Aufhebung der Lesebreite fuer Einstiege, deren Ueberschrift die volle Spalte nutzen soll. */
.gsIntro--wide{max-width:none}
.gsEyebrow{display:inline-block;font-family:var(--font-display);font-weight:var(--weight-semi);
  font-size:var(--text-base);letter-spacing:var(--tracking-wide);text-transform:uppercase;
  color:var(--color-accent);margin-bottom:var(--s-2)}
.gsH1{font-family:var(--font-display);font-weight:var(--weight-black);font-size:var(--text-display);
  line-height:var(--leading-tight);letter-spacing:var(--tracking-tighter);margin:0 0 var(--s-4)}
.gsH2{font-family:var(--font-display);font-weight:var(--weight-bold);font-size:var(--text-3xl);
  line-height:var(--leading-tight);letter-spacing:var(--tracking-tight);margin:0 0 var(--s-4)}
.gsH3{font-family:var(--font-display);font-weight:var(--weight-bold);font-size:var(--text-lg);
  margin:0 0 var(--s-2)}
.gsLead{font-size:var(--text-md);line-height:var(--leading-normal);margin:0 0 var(--s-2);
  color:var(--color-text-muted)}
.gsProse p{font-size:var(--text-base);line-height:var(--leading-relaxed);
  color:var(--color-text-muted);margin:0 0 var(--s-4)}
.gsProse p:last-child{margin-bottom:0}
.gsProseList{margin:0 0 var(--s-4);padding-left:var(--s-6)}
.gsProseList li{font-size:var(--text-base);line-height:var(--leading-relaxed);
  color:var(--color-text-muted);margin:0 0 var(--s-2)}

/* ---------- Karten / Listen ---------- */
.gsCard{background:var(--color-surface-soft);border-radius:var(--radius-xl);padding:var(--s-8);
  border:var(--border-hair) solid var(--color-line-soft)}
.gsCard--soft{background:var(--color-surface-soft);border-radius:var(--radius-2xl);padding:var(--s-8);
  border-left:var(--border-accent) solid var(--color-action)}
.gsChecks{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--s-3)}
.gsChecks li{display:flex;gap:var(--s-2);align-items:flex-start;font-size:var(--text-base);
  line-height:var(--leading-snug);color:var(--color-text)}
.gsCheck{flex:none;margin-top:var(--border-hair);color:var(--color-accent)}
.gsCheck--invert{color:var(--color-text-invert)}

/* ---------- Raster: mobiler Default einspaltig, Stufen per min-width ---------- */
.gsGrid2,.gsGrid3,.gsGrid4{display:grid;grid-template-columns:1fr;gap:var(--space-gap)}
.gsSplit{display:grid;grid-template-columns:1fr;gap:var(--s-12)}
.gsStickyAside{position:static}
.gsMedia{position:relative;min-height:var(--size-blob-xl)}
.gsHideMobile{display:none}
@media (min-width:641px){
  .gsGrid2,.gsGrid3,.gsGrid4{grid-template-columns:repeat(2,1fr)}
}
@media (min-width:1025px){
  .gsGrid3{grid-template-columns:repeat(3,1fr)}
  .gsGrid4{grid-template-columns:repeat(4,1fr)}
  .gsSplit{grid-template-columns:1fr 1fr;align-items:center}
  .gsSplit--23{grid-template-columns:2fr 1fr}
  .gsContactGrid{grid-template-columns:.78fr 1.22fr}
  .gsStickyAside{position:sticky;top:var(--s-25);align-self:start}
  .gsMedia{min-height:var(--height-media)}
  .gsHideMobile{display:block}
}

/* ---------- Unterseiten-Hero ---------- */
.gsSubHero{position:relative;overflow:hidden;background:var(--gradient-hero-dark);
  color:var(--color-text-invert);padding:var(--space-hero) var(--space-gutter)}
.gsSubHero .gsEyebrow{color:var(--color-accent-invert)}
.gsSubHero .gsH1{color:var(--color-text-invert)}
.gsSubHero .gsLead{color:var(--color-text-invert-strong)}
.gsHeroBullets{list-style:none;margin:var(--s-6) 0 var(--s-7);padding:0;display:grid;
  gap:var(--s-3);max-width:var(--width-media)}
.gsHeroBullets li{display:flex;gap:var(--s-3);align-items:flex-start;font-size:var(--text-base);
  line-height:var(--leading-snug);color:var(--color-text-invert-strong)}
.gsCtaRow{display:flex;flex-wrap:wrap;gap:var(--s-4);align-items:center}

/* Unterseiten-Hero mit Motiv. Mobil steht das Motiv oben, randlos bis an die Sectionkanten,
   und laeuft nach unten in den Grund aus; danach Abstand zum Text. Ausgeblendet wird nur die
   Unterkante – eine Ausblendung nach oben wuerde bei Personenmotiven die Koepfe abschneiden
   (die sitzen immer im oberen Bilddrittel). Die Umsortierung laeuft ueber `order`, damit die
   H1 in der Quellreihenfolge vor dem Bild bleibt. */
.gsSubHero--media{display:flex;flex-direction:column}
.gsSubHeroMedia{display:block;order:-1;flex:none;height:var(--height-hero-media);
  margin:calc(var(--space-hero) * -1) calc(var(--space-gutter) * -1) var(--s-4);
  -webkit-mask-image:var(--mask-fade-block-end);mask-image:var(--mask-fade-block-end)}
/* Ab 1025px steht das Motiv rechts und wird per Alpha-Maske nach links ausgeblendet – dort
   laeuft der Text seitlich daneben, nicht darunter. Zwingend an @supports gebunden: ohne
   Maskenunterstuetzung laege das Bild deckend ueber dem Text. Fallback ist dann der mobile
   Zustand, also Motiv oben. Nicht herauslösen. */
@supports ((mask-image:linear-gradient(transparent,transparent)) or (-webkit-mask-image:linear-gradient(transparent,transparent))){
  @media (min-width:1025px){
    .gsSubHero--media{display:block}
    .gsSubHeroMedia{position:absolute;top:0;right:0;bottom:0;width:52%;height:auto;margin:0;
      z-index:var(--z-raised);pointer-events:none;
      -webkit-mask-image:var(--mask-fade-inline-start);mask-image:var(--mask-fade-inline-start)}
    .gsSubHero--media > .gsWrap{position:relative;z-index:var(--z-content)}
    .gsSubHero--media .gsH1,
    .gsSubHero--media .gsLead,
    .gsSubHero--media .gsCtaRow{max-width:var(--width-media)}
  }
}

/* ---------- Nummerierte Schritte ---------- */
.gsStep{position:relative;padding-top:var(--s-4);
  border-top:var(--border-thick) solid var(--color-line-accent)}
.gsStepN{font-family:var(--font-display);font-weight:var(--weight-black);font-size:var(--text-3xl);
  line-height:var(--leading-flat);color:var(--color-accent);display:block;margin-bottom:var(--s-2)}

/* ---------- FAQ-Disclosure ---------- */
details > summary{list-style:none;cursor:pointer}
details > summary::-webkit-details-marker{display:none}
.gsFaqList{display:flex;flex-direction:column;gap:var(--s-3)}
.gsFaqItem{background:var(--color-surface-alt);border:var(--border-hair) solid var(--color-line-mid);
  border-radius:var(--radius-lg)}
.gsFaqItem > summary{display:flex;justify-content:space-between;align-items:center;gap:var(--s-4);
  min-height:var(--size-control);padding:var(--s-4) var(--s-5);font-family:var(--font-display);
  font-weight:var(--weight-semi);font-size:var(--text-base);color:var(--color-text);
  transition:color var(--duration-base) var(--ease-base)}
.gsFaqItem > summary:hover,.gsFaqItem > summary:focus-visible{color:var(--color-accent)}
.gsFaqItem > summary h3{margin:0;font-size:var(--text-base);font-weight:var(--weight-semi);
  font-family:inherit}
.gsFaqIcon{flex:none;width:var(--s-6);height:var(--s-6);color:var(--color-accent);display:grid;
  place-items:center;font-size:var(--text-md);font-weight:var(--weight-bold);
  line-height:var(--leading-flat)}
.gsFaqA{padding:0 var(--s-5) var(--s-5);font-size:var(--text-base);
  line-height:var(--leading-relaxed);color:var(--color-text-muted)}

/* ---------- CTA-Band ---------- */
.gsCtaBand{background:var(--color-action);color:var(--color-text-invert);
  padding:var(--space-section) var(--space-gutter);position:relative;overflow:hidden;text-align:center}
.gsCtaBand .gsH2{color:var(--color-text-invert)}
.gsCtaBand a.gsInline{color:var(--color-text-invert);text-decoration-color:var(--color-line-invert-strong)}
.gsCtaBand a.gsInline:hover{color:var(--color-surface);text-decoration-color:var(--color-text-invert)}

/* ---------- Tabellen (2D-Scroll erlaubte Ausnahme) ---------- */
.gsTableWrap{overflow-x:auto}
.gsTable{width:100%;border-collapse:collapse;font-size:var(--text-base);min-width:32.5rem}
.gsTable th,.gsTable td{padding:var(--s-3) var(--s-4);
  border-bottom:var(--border-hair) solid var(--color-line-mid);text-align:left}
.gsTable thead th{font-family:var(--font-display);font-weight:var(--weight-bold);
  color:var(--color-text);background:var(--color-accent-soft)}
.gsTable tbody th{font-weight:var(--weight-semi);color:var(--color-text-muted)}
.gsTable td{color:var(--color-text-muted)}

/* ---------- Wochenplan ---------- */
.gsCalWrap{overflow-x:auto}
table.gsCal{width:100%;min-width:41.25rem;border-collapse:separate;border-spacing:var(--s-2)}
.gsCal thead th{font-family:var(--font-display);font-weight:var(--weight-bold);font-size:var(--text-sm);
  letter-spacing:var(--tracking-caps);text-transform:uppercase;color:var(--color-brand);
  padding:var(--s-1) var(--s-1) var(--s-2);
  border-bottom:var(--border-thick) solid var(--color-accent-soft);text-align:center}
.gsCal thead th:first-child{border-bottom:none}
.gsCal tbody th[scope="row"]{font-family:var(--font-display);font-weight:var(--weight-bold);
  font-size:var(--text-sm);color:var(--color-text-subtle);text-align:right;white-space:nowrap;
  padding-right:var(--s-2);width:var(--s-15)}
.gsCalBand th{font-family:var(--font-display);font-weight:var(--weight-bold);font-size:var(--text-sm);
  letter-spacing:var(--tracking-caps);text-transform:uppercase;color:var(--color-accent);
  text-align:left;background:var(--color-surface);border-radius:var(--radius-pill);
  padding:var(--s-2) var(--s-5)}
.gsCal td{height:var(--s-12);background:var(--color-surface-sand);
  border:var(--border-hair) dashed var(--color-line-dashed);border-radius:var(--radius-md);padding:0}
.gsCal td.on{background:var(--kurs-flaeche,var(--color-surface-alt));
  border:var(--border-hair) solid var(--color-line);
  border-left:var(--border-marker) solid var(--kurs-linie,var(--color-action));
  padding:var(--s-2) var(--s-3)}
.gsCalName{font-size:var(--text-sm);font-weight:var(--weight-semi);line-height:var(--leading-snug);
  color:var(--color-text)}

/* Kursfarben: `.gsKurs--<slug>` traegt nur das Farbpaar, verbraucht wird es von der
   Tabellenzelle und vom Kurs-Badge. Gleiche Kursart = gleiche Klasse = gleiche Farbe. */
.gsKursPill{display:inline-block;font-size:var(--text-base);font-weight:var(--weight-semi);
  color:var(--color-text);padding:var(--s-2) var(--s-4);border-radius:var(--radius-pill);
  background:var(--kurs-flaeche,var(--color-surface-alt));
  border:var(--border-hair) solid var(--color-line);
  border-left:var(--border-marker) solid var(--kurs-linie,var(--color-action))}
.gsKurs--cardio-strength{--kurs-linie:var(--color-kurs-cardio-strength);--kurs-flaeche:var(--color-kurs-cardio-strength-soft)}
.gsKurs--zumba{--kurs-linie:var(--color-kurs-zumba);--kurs-flaeche:var(--color-kurs-zumba-soft)}
.gsKurs--total-body{--kurs-linie:var(--color-kurs-total-body);--kurs-flaeche:var(--color-kurs-total-body-soft)}
.gsKurs--bodywork{--kurs-linie:var(--color-kurs-bodywork);--kurs-flaeche:var(--color-kurs-bodywork-soft)}
.gsKurs--core-floor{--kurs-linie:var(--color-kurs-core-floor);--kurs-flaeche:var(--color-kurs-core-floor-soft)}
.gsKurs--stability{--kurs-linie:var(--color-kurs-stability);--kurs-flaeche:var(--color-kurs-stability-soft)}
.gsKurs--mobility{--kurs-linie:var(--color-kurs-mobility);--kurs-flaeche:var(--color-kurs-mobility-soft)}
.gsKurs--stretching{--kurs-linie:var(--color-kurs-stretching);--kurs-flaeche:var(--color-kurs-stretching-soft)}
.gsKurs--maennerturnen{--kurs-linie:var(--color-kurs-maennerturnen);--kurs-flaeche:var(--color-kurs-maennerturnen-soft)}
.gsKurs--qigong{--kurs-linie:var(--color-kurs-qigong);--kurs-flaeche:var(--color-kurs-qigong-soft)}
.gsKurs--sessel-vital{--kurs-linie:var(--color-kurs-sessel-vital);--kurs-flaeche:var(--color-kurs-sessel-vital-soft)}
.gsKurs--dance-cardio{--kurs-linie:var(--color-kurs-dance-cardio);--kurs-flaeche:var(--color-kurs-dance-cardio-soft)}
.gsKurs--fun-dance{--kurs-linie:var(--color-kurs-fun-dance);--kurs-flaeche:var(--color-kurs-fun-dance-soft)}

/* ---------- News-Karten (Aktuelles) ----------
   Zwei Aktionen nebeneinander erst im Desktop-Rahmen. Bewusst **nicht** `gsGrid2`:
   das stuft schon ab 641px auf zwei Spalten, und zwei Flyer-Karten in je ~300px
   sind unlesbar. Deshalb ein eigenes Raster mit der Stufe bei 1025px. */
.gsNewsGrid{display:grid;grid-template-columns:1fr;gap:var(--space-gap)}
.gsNewsCard{background:var(--color-surface-soft);border-radius:var(--radius-xl);
  padding:var(--s-8);border:var(--border-hair) solid var(--color-line-soft);
  scroll-margin-top:var(--space-header)}
/* Die Karten tragen die Sprungmarken (#herbstaktion-2026, #powerplate-abo). Ohne
   `scroll-margin-top` landet der Kartenkopf unter dem fixierten Header – der Wert ist
   genau dessen Hoehe (dieselbe Groesse, die `.gsShell` als `padding-top` nutzt). */
.gsNewsFig{margin:0 0 var(--s-6)}
/* Der Flyer bleibt vollstaendig sichtbar (kein `cover`-Anschnitt): Hochformat 1:1,42,
   in der Breite gedeckelt und zentriert. Gross gelesen wird er in der Lightbox. */
.gsNewsFigLink{display:block;position:relative;max-width:var(--width-news-fig);
  margin:0 auto var(--s-2);border-radius:var(--radius-lg);overflow:hidden;
  border:var(--border-hair) solid var(--color-line-soft);box-shadow:var(--shadow-card-sm)}
.gsNewsZoom{position:absolute;bottom:var(--s-3);right:var(--s-3);
  display:grid;place-items:center;width:var(--size-control);height:var(--size-control);
  border-radius:var(--radius-pill);background:var(--color-surface);color:var(--color-text)}
.gsNewsFigLink:hover .gsNewsZoom,
.gsNewsFigLink:focus-visible .gsNewsZoom{background:var(--color-accent-soft);
  color:var(--color-brand-dark)}
.gsNewsCap{font-size:var(--text-sm);line-height:var(--leading-normal);
  color:var(--color-text-subtle);text-align:center}
.gsNewsProse{margin:0 0 var(--s-6)}
/* `.gsChecks` setzt `margin:0` und liegt in derselben Datei – eine Abstands-Utility im
   Markup wuerde davon ueberschrieben (Komponenten laden nach Utilities). Der Abstand
   zwischen Liste und Folgeinhalt (Zwischentitel, CTA-Reihe) kommt deshalb von hier. */
.gsNewsCard .gsChecks{margin:0 0 var(--s-6)}
/* Die beiden Schaltflaechen stehen in der Karte untereinander (Kundenvorgabe) – im
   halbbreiten Korpus bliebe nebeneinander zu wenig Breite fuer die Beschriftungen.
   `align-items:stretch` genuegt fuer die volle Breite, die Beschriftung wird zentriert. */
.gsNewsCard .gsCtaRow{flex-direction:column;align-items:stretch}
.gsNewsCard .gsCtaRow > a{justify-content:center}
@media (min-width:1025px){
  .gsNewsGrid{grid-template-columns:repeat(2,1fr)}
  /* Laeuft eine Aktion aus (September 2026), soll die letzte Karte nicht halbbreit mit
     leerer Nachbarspalte stehen. */
  .gsNewsGrid > .gsNewsCard:only-child{grid-column:1 / -1}
}
@media (min-width:1025px) and (prefers-reduced-motion:no-preference){
  .gsNewsZoom{transition:background var(--duration-fast),color var(--duration-fast)}
}

/* ---------- Lightbox (natives <dialog>) ----------
   Wie das Aktions-Modal von `main.js` erzeugt, steht also in keinem Markup. Ohne JS
   bleibt der Flyer ein normaler Link auf die Bilddatei – die Vergroesserung ist damit
   auch ohne Skript erreichbar.

   Der Dialog ist hier **kein Kasten um das Bild**, sondern eine randlose, durchsichtige
   Buehne ueber dem Viewport, die das Bild mittig stellt; sichtbar ist allein das Bild.
   Grund: `<dialog>` ist per UA-Stylesheet `width:fit-content` mit `inset-inline:0`. Ein
   Kasten muesste sich also per Shrink-to-fit um das Bild legen – das misslingt, sobald
   `max-height` das Bild verkleinert, weil die intrinsische Breitenberechnung eines
   ersetzten Elements die Hoehenbegrenzung nicht beruecksichtigt. Der Kasten bliebe so
   breit wie das unskalierte Bild und das Bild klebte links darin.
   **Deshalb `width`/`height` hier nicht auf `auto` oder `fit-content` zurueckdrehen.** */
.gsLightbox[open]{display:flex;align-items:center;justify-content:center}
.gsLightbox{position:fixed;inset:0;width:100%;height:100%;max-width:none;max-height:none;
  margin:0;padding:var(--space-gutter);border:0;background:transparent;box-shadow:none}
.gsLightbox::backdrop{background:var(--color-scrim-modal)}
/* Das Bild traegt die sichtbare Flaeche. `100%` ist dank `border-box` der Viewport
   abzueglich der Buehnen-Polsterung – es passt also immer ohne Scrollen hinein. */
.gsLightboxImg{display:block;width:auto;height:auto;max-width:100%;max-height:100%;
  border-radius:var(--radius-xl);box-shadow:var(--shadow-card-lg)}

/* ---------- Modal (natives <dialog>) ----------
   Bewusst das native Element: Fokusfalle, Esc und Fokus-Rueckgabe kommen von der
   Plattform, es braucht keine eigene Fokus-Logik. Das Dialog-Element selbst wird von
   `main.js` erzeugt (siehe dort) – im Markup steht es nirgends, deshalb auch kein
   initial versteckter Inhalt. Der identische Inhalt ist als normale Seite unter
   /aktuelles#herbstaktion-2026 erreichbar. */
.gsModal{width:calc(100% - var(--s-8));max-width:var(--width-narrow);
  border:0;padding:0;background:var(--color-surface-alt);color:var(--color-text);
  border-radius:var(--radius-3xl);box-shadow:var(--shadow-card-lg);
  border-top:var(--border-accent) solid var(--color-action)}
.gsModal::backdrop{background:var(--color-scrim-modal)}
.gsModalBody{padding:var(--s-8)}
.gsModalClose{position:absolute;top:var(--s-4);right:var(--s-4);
  display:grid;place-items:center;width:var(--size-control);height:var(--size-control);
  min-height:var(--size-control);border:0;border-radius:var(--radius-pill);
  background:var(--color-surface);color:var(--color-text);cursor:pointer}
.gsModalClose:hover{background:var(--color-accent-soft);color:var(--color-brand-dark)}
@media (min-width:1025px){
  .gsModalBody{padding:var(--s-12)}
}
/* Flyer-Variante: das Modal ist im Wesentlichen der Aktionsflyer (2:3), darunter eine
   schmale Verweisleiste. Die Breite wird aus der verfuegbaren Hoehe gerechnet, nicht per
   Shrink-to-fit um das Bild gelegt (s. gsLightbox): Viewport-Hoehe abzueglich Rand und
   Reserve fuer die Leiste, mal 2/3. So passt der Flyer ohne Scrollen und ohne Leerraum
   seitlich, und er waechst mit dem Bildschirm bis zum Deckel von 40rem (640px).
   Mobil/flach: Rand --s-8, Reserve --s-30 – reicht fuer zwei umgebrochene Button-Zeilen;
   die Reserve uebersteigt die einzeilige Leiste, der UA-Deckel (s. u.) greift hier also nicht.
   Ab 481px Breite und 600px Hoehe passen beide Buttons sicher in eine Zeile (76px), die
   Reserve sinkt auf --s-20 und der Flyer wird entsprechend groesser. Der Hoehenrand
   --s-10 (40px) liegt bewusst ueber dem UA-Deckel max-height:calc(100% - 2em - 6px) = 38px,
   sonst schnitte overflow:hidden die Leiste ab.
   Die vh-Zeile ist jeweils der Fallback fuer Browser ohne dvh. */
.gsModal--flyer{max-width:none;overflow:hidden;border-top:0;
  width:min(calc(100% - var(--s-8)), 40rem, calc((100vh - var(--s-8) - var(--s-30)) * 2 / 3));
  width:min(calc(100% - var(--s-8)), 40rem, calc((100dvh - var(--s-8) - var(--s-30)) * 2 / 3))}
@media (min-width:481px) and (min-height:600px){
  .gsModal--flyer{
    width:min(calc(100% - var(--s-8)), 40rem, calc((100vh - var(--s-10) - var(--s-20)) * 2 / 3));
    width:min(calc(100% - var(--s-8)), 40rem, calc((100dvh - var(--s-10) - var(--s-20)) * 2 / 3))}
}
.gsModalFlyerImg{display:block;width:100%;height:auto}
.gsModalFlyerBar{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--s-2);padding:var(--s-4)}
.gsModalFlyerBar a{flex:1 1 auto}

/* ---------- Team-Karten ---------- */
.gsTeamGrid{display:grid;grid-template-columns:1fr;gap:var(--space-gap);
  list-style:none;margin:0;padding:0}
.gsTeamCardV{background:var(--color-surface-alt);border:var(--border-hair) solid var(--color-line-soft);
  border-radius:var(--radius-2xl);overflow:hidden}
.gsTeamCardV picture{display:block}
.gsTeamPhoto{display:block;width:100%;height:auto;aspect-ratio:3/4;object-fit:cover;
  object-position:center top;background:var(--color-accent-soft)}
.gsTeamBody{padding:var(--s-4) var(--s-5) var(--s-5)}
.gsTeamName{font-family:var(--font-display);font-weight:var(--weight-bold);font-size:var(--text-base);
  margin:0;color:var(--color-text)}
/* Silbentrennung explizit mit Praefix: Safari/iOS kennt nur -webkit-hyphens, die globale
   Regel in utilities.css greift dort nicht. Lange Komposita ("Bewegungswissenschaftlerin")
   sprengen sonst die schmale Karte. hyphenate-limit-chars verhindert Kurzreste (Chromium). */
.gsTeamRole{margin:var(--s-1) 0 0;font-size:var(--text-base);color:var(--color-text-subtle);
  -webkit-hyphens:auto;hyphens:auto;hyphenate-limit-chars:6 3 3}
@media (min-width:481px){.gsTeamGrid{grid-template-columns:repeat(2,1fr)}}
@media (min-width:1025px){.gsTeamGrid{grid-template-columns:repeat(4,1fr)}}

/* ---------- Definitionsliste ---------- */
.gsDl{display:grid;grid-template-columns:1fr;gap:0;
  font-size:var(--text-base);line-height:var(--leading-normal)}
.gsDl dt{font-weight:var(--weight-semi);color:var(--color-text)}
.gsDl dd{margin:0 0 var(--s-3);color:var(--color-text-muted)}
@media (min-width:641px){
  .gsDl{grid-template-columns:auto 1fr;gap:var(--s-2) var(--s-5)}
  .gsDl dd{margin:0}
}

/* ---------- Karten-Embed (Anfahrt, hinter CMP) ---------- */
.gsMapBox{position:relative;width:100%;height:var(--height-map)}
.gsMapBox iframe{display:block;width:100%;height:100%;border:0}

/* ---------- Formulare (Formix + EverCaptcha) ---------- */
.gsForm{display:flex;flex-direction:column;gap:var(--s-4)}
.gsField{display:flex;flex-direction:column;gap:var(--s-1)}
.gsField label{font-weight:var(--weight-semi);font-size:var(--text-base);color:var(--color-text)}
.gsField input,.gsField textarea,.gsField select{font:inherit;font-size:var(--text-base);
  color:var(--color-text);background:var(--color-surface-alt);
  border:var(--border-hair) solid var(--color-line-strong);border-radius:var(--radius-md);
  padding:var(--s-3) var(--s-3);width:100%;min-height:var(--size-control)}
.gsField input:focus,.gsField textarea:focus,.gsField select:focus{
  outline:3px solid var(--color-focus);outline-offset:1px;border-color:var(--color-focus)}
.gsField textarea{min-height:var(--s-30);resize:vertical}
.gsFormNote{font-size:var(--text-base);color:var(--color-text-subtle);margin:0}
.gsCheckField{display:flex;align-items:flex-start;gap:var(--s-3);min-height:var(--size-control)}
.gsCheckField input{width:var(--s-5);height:var(--s-5);flex:none;margin-top:var(--s-1);
  accent-color:var(--color-action)}
.gsCheckField label{font-weight:var(--weight-regular);font-size:var(--text-base);
  color:var(--color-text-muted);line-height:var(--leading-normal)}
.gsHoneypot{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* Pflichtfeld-Meldung ohne Skript.
   Mobile Browser zeigen die native Validierungs-Bubble nicht oder nur
   Millisekunden lang – der Absende-Versuch scheitert dort stumm. Die
   Feldgruppe erzeugt die Meldung deshalb selbst.
   Traeger ist .gsField, nicht das Control: auf input/select/textarea
   rendert kein Browser Pseudo-Elemente (ersetzte Elemente).
   :user-invalid statt :invalid – greift erst nach Interaktion bzw. nach
   einem Absende-Versuch, nie schon beim Laden.
   Bewusst nicht per :focus unterdrueckt: nach fehlgeschlagenem Absenden
   fokussiert der Browser genau das erste fehlerhafte Feld – dort muss die
   Meldung stehen bleiben. Der Fehler traegt Text, nie nur Farbe (Kap. 9).
   Browser ohne :has()/:user-invalid verwerfen die Regeln als ungueltigen
   Selektor und zeigen wie heute nichts – kein neuer Nachteil. */
.gsField:has(:user-invalid)::after{content:"Dieses Feld muss ausgefüllt sein";
  font-size:var(--text-base);font-weight:var(--weight-semi);
  line-height:var(--leading-snug);color:var(--color-danger)}
/* Gefuellt, aber formal falsch – „muss ausgefuellt sein“ waere hier
   sachlich falsch. Der Leer-Test laeuft ueber :placeholder-shown und gilt
   deshalb nur fuer Controls mit placeholder-Attribut (date/select haben
   keins und wuerden sonst dauerhaft als „gefuellt“ gelten). */
.gsField:has(input[placeholder]:user-invalid:not(:placeholder-shown))::after,
.gsField:has(textarea[placeholder]:user-invalid:not(:placeholder-shown))::after{
  content:"Bitte prüfen Sie diese Eingabe"}
.gsField:has(input[type="email"][placeholder]:user-invalid:not(:placeholder-shown))::after{
  content:"Bitte geben Sie eine gültige E-Mail-Adresse ein"}
.gsField:has(select:user-invalid)::after{content:"Bitte wählen Sie einen Eintrag aus"}
/* Wunschdatum: leer, vor der Vorlaufzeit (min aus main.js) oder ein Tag ohne
   Betreuung teilen eine Meldung – der Hinweis darunter nennt den konkreten
   fruehesten Termin, den kann CSS nicht kennen. */
.gsField:has(input[type="date"]:user-invalid)::after{
  content:"Bitte wählen Sie ein mögliches Datum"}
/* Steht nach der :focus-Regel, damit der rote Rand auch im Fokus sichtbar
   bleibt – die gruene Fokus-Outline liegt unabhaengig darueber. */
.gsField input:user-invalid,.gsField select:user-invalid,.gsField textarea:user-invalid{
  border-color:var(--color-danger)}
/* Nur beim Wunschdatum steht ein Hinweis-Absatz in der Feldgruppe. Die Meldung
   ist ein Flex-Item mit order 0 und rueckt damit vor den Hinweis, also direkt
   unter das Feld - ohne Fehler aendert die Regel nichts. */
.gsField .gsFormNote{order:1}

/* ---------- Consent-Aufforderung fuer das Kursplan-Widget ----------
   Einmalig auf /fitnesskurse. Sichtbar, solange der Dienst nicht
   freigegeben ist; der Knopf traegt data-privacy-control="eversports"
   und wird von der CMP abgehoert.
   Ausgeblendet wird die Aufforderung am Widget selbst: sobald der Loader
   in den Container rendert, hat der Container Kinder. Bewusst nicht an
   einem CMP-Zustand aufgehaengt – welche Klasse privacyControl im
   Freigabefall setzt, ist nicht dokumentiert; das vorhandene Widget ist
   das verlaessliche Signal. Geschwister-Kombinator ~ statt +, weil das
   Loader-Script als Element zwischen beiden steht.
   Ohne JS laeuft auch die CMP nicht, der Knopf waere funktionslos –
   dann traegt der noscript-Absatz. */
[data-eversports-widget-id]:has(*) ~ .gsConsentBox{display:none}
.no-js .gsConsentBox{display:none}

/* ---------- Mitgliedschaftskarten ---------- */
.gsPriceBar{background:var(--color-accent-soft)}
.gsPriceDivider{background:var(--color-line-divider)}
.gsPlan{position:relative;overflow:hidden;display:flex;flex-direction:column;
  border-radius:var(--radius-3xl);box-shadow:var(--shadow-card-sm);
  transition:transform var(--duration-base) var(--ease-base),box-shadow var(--duration-base) var(--ease-base)}
.gsPlanHead{padding:var(--s-6) var(--s-7) var(--s-5)}
.gsPlanName{font-family:var(--font-display);font-weight:var(--weight-black);font-size:var(--text-lg);
  margin:0 0 var(--s-1)}
.gsPlanPrice{font-family:var(--font-display);font-weight:var(--weight-black);font-size:var(--text-lg);
  margin:0}
.gsPlanPrice small{font-weight:var(--weight-semi);font-size:var(--text-base)}
.gsPlanBody{flex:1;padding:var(--s-6) var(--s-7) var(--s-7)}
.gsPlanDesc{margin:0 0 var(--s-5);font-size:var(--text-base);line-height:var(--leading-normal)}
.gsPlanList{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--s-3)}
.gsPlanList li{display:flex;gap:var(--s-3);align-items:flex-start;font-size:var(--text-base);
  line-height:var(--leading-snug)}
.gsPlanDot{flex:none;width:var(--s-2);height:var(--s-2);margin-top:var(--s-2);
  border-radius:var(--radius-circle)}
.gsPlan--bronze{border:var(--border-hair) solid var(--color-bronze-400)}
.gsPlan--bronze .gsPlanHead{background:var(--gradient-bronze);color:var(--color-silver-ink)}
.gsPlan--bronze .gsPlanBody{background:var(--color-bronze-50);color:var(--color-bronze-ink)}
.gsPlan--bronze .gsPlanDot{background:var(--color-bronze-600)}
.gsPlan--silber{border:var(--border-hair) solid var(--color-silver-500)}
.gsPlan--silber .gsPlanHead{background:var(--gradient-silver);color:var(--color-silver-ink)}
.gsPlan--silber .gsPlanBody{background:var(--color-silver-50);color:var(--color-silver-ink)}
.gsPlan--silber .gsPlanDot{background:var(--color-silver-700)}
.gsPlan--gold{border:var(--border-hair) solid var(--color-gold-400)}
.gsPlan--gold .gsPlanHead{background:var(--gradient-gold);color:var(--color-silver-ink)}
.gsPlan--gold .gsPlanBody{background:var(--color-gold-50);color:var(--color-gold-ink)}
.gsPlan--gold .gsPlanDot{background:var(--color-gold-600)}
.gsPlan::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:var(--gradient-sheen);transform:translateX(-120%);
  transition:transform var(--duration-sheen) var(--ease-base)}
.gsPlan:hover{transform:translateY(-4px);box-shadow:var(--shadow-card-xl)}
.gsPlan:hover::after{transform:translateX(120%)}
@media (hover:none){.gsPlan::after{display:none}}
@media (prefers-reduced-motion:reduce){
  .gsPlan{transition:none}
  .gsPlan:hover{transform:none}
  .gsPlan::after{display:none}
}
/* Preisleiste: mobil untereinander ohne Trennlinie */
.gsPriceBar{flex-direction:column;align-items:flex-start}
.gsPriceDivider{display:none}
@media (min-width:641px){
  .gsPriceBar{flex-direction:row;align-items:center}
  .gsPriceDivider{display:block}
}

/* ---------- Footer ---------- */
.gsFooter{position:relative;background:var(--color-surface-dark);
  color:var(--color-text-invert-muted);padding:var(--space-section) var(--space-gutter) var(--s-12);
  overflow:hidden}
.gsFooterGrid{display:grid;grid-template-columns:1fr;gap:var(--s-8);
  align-items:start;position:relative;max-width:var(--width-page);margin:0 auto}
.gsFooterHead{display:block;font-family:var(--font-display);font-weight:var(--weight-semi);
  font-size:var(--text-base);letter-spacing:var(--tracking-wide);text-transform:uppercase;
  color:var(--color-accent-invert);margin-bottom:var(--s-4)}
/* Mobil ist die 44px-Zielgroesse der Links gleichzeitig der Zeilenabstand;
   im Desktop-Rahmen die kompakte Zeilenfuehrung (s. Abweichung in CLAUDE.md). */
.gsFooterNav{display:flex;flex-direction:column;align-items:flex-start;gap:0;
  font-size:var(--text-base)}
.gsFooterNav a{color:var(--color-text-invert-muted);text-decoration:none;
  min-height:var(--size-control);display:flex;align-items:center;
  line-height:var(--leading-tight);
  transition:color var(--duration-base) var(--ease-base)}
@media (min-width:1025px){
  .gsFooterNav{gap:var(--s-3)}
  .gsFooterNav a{min-height:0;line-height:var(--leading-relaxed)}
}
.gsFooterNav a:hover{text-decoration:underline}
.gsFooterNav a[aria-current="page"]{color:var(--color-text-invert);font-weight:var(--weight-bold)}
.gsFooterNav a.gsFooterSub{color:var(--color-text-invert-faint);margin-left:var(--s-4);
  border-left:var(--border-hair) solid var(--color-line-invert);padding-left:var(--s-3)}
.gsLogoFooter{display:block;height:var(--size-logo-footer);width:auto}
@media (min-width:521px){
  .gsFooterGrid{grid-template-columns:repeat(3,1fr)}
  .gsFooterGrid > div:first-child{grid-column:1/-1}
}
@media (min-width:821px){
  .gsFooterGrid{grid-template-columns:1.5fr 1fr 1fr 1fr;gap:var(--s-12)}
  .gsFooterGrid > div:first-child{grid-column:auto}
}
