/* ===================================================================
   KONFEKTORY — STARTSEITE  ·  DIE SORTENTAFEL
   -------------------------------------------------------------------
   Kristina fotografiert ihre Macarons aufgeschnitten: vier Haelften,
   gestapelt, Fuellung offen. Tuerkise Schale mit gelbem Kern, Neongruen
   mit Lila, Maracuja-Gorgonzola. Das IST die Marke — "Ausgefallen.
   Lecker. Anders." muss hier nichts behaupten, es steht da.

   Vier Haelften = vier Fallblaetter. Die Tafel blaettert durch die
   Sorten, jedes Band mit Versatz, der Schein dahinter zieht in die
   Farbe der neuen Sorte. Lebendig ohne eine Sekunde Video.

   Heller, warmer Salbei-Grund: Die Produktfarben bleiben ueber einen sanften
   Schein sichtbar, waehrend Text und Navigation dunkle, lesbare Akzenttoene
   verwenden.

   Kein Pin, kein Snap, kein Scroll-Hijack: der Hero scrollt normal weg.
   Copy + beide CTAs stehen ab Sekunde 0, ohne JS, ohne Bild.

   Laedt NACH pages.css -> erbt Tokens/Nav/Footer/Buttons/Reveal.
   Namensraum: .tafel-*  · cookielos, RM-sicher.
   =================================================================== */

/* ============ 0 · Home-lokale Tokens ============ */
:root{
  --tafel-bg:#EEF3EB;        /* heller, warmer Salbei-Grund */
  --tafel-bg-bot:#F7F8F3;    /* nahezu Porzellan fuer eine ruhige Naht */
  --tafel-on:#22271F;        /* Schrift auf hellem Grund */
  --tafel-on-mute:#4B5346;   /* Sekundaerschrift auf hellem Grund */

  /* Wird pro Sorte von home.js gesetzt und ist der ganze Farbwechsel.
     Startwert = Bounty, damit der Hero ohne JS nicht farblos dasteht. */
  --sorte:#087985;
}

/* Ohne @property waere --sorte fuer den Browser ein Stueck Text, und Text
   interpoliert nicht: der Schein (ein radial-gradient, also background-IMAGE)
   wuerde hart umspringen. transition:background greift bei Gradienten prinzipiell
   nicht. Als typisierte Custom Property ist --sorte eine echte Farbe — der
   Browser rechnet die Zwischenwerte und zeichnet den Gradienten Frame fuer Frame
   neu. Ein Wert morpht, alles was ihn liest morpht mit.
   Ohne @property-Support faellt es auf harte Farbwechsel zurueck: nicht schoen,
   aber nicht kaputt. */
@property --sorte{
  syntax:'<color>';
  inherits:true;
  initial-value:#087985;
}

/* ============ 1 · BUEHNE ============ */
/* Grid statt absoluter Positionierung: Text und Tafel koennen sich damit
   nicht ueberlappen — die Textkollision, an der der erste Hero gestorben
   ist, wird hier strukturell unmoeglich statt per Sicherheitsabstand. */
.tafel-hero{position:relative;min-height:100svh;overflow:hidden;
  background:linear-gradient(180deg,var(--tafel-bg) 0%,var(--tafel-bg) 62%,var(--tafel-bg-bot) 100%);
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.85fr);
  align-items:center;gap:clamp(1rem,4vw,4rem);
  /* Der Hintergrund laeuft ueber die volle Breite, der INHALT bleibt bei
     --wrap-wide wie der Rest der Seite. Ohne das reisst auf einem 3440er
     Monitor ein 1300 px breites Loch zwischen Text und Tafel auf. */
  padding:calc(var(--nav-h) + 4svh) max(var(--edge),calc((100% - var(--wrap-wide)) / 2)) 6svh;
  /* HIER STAND: transition:--sorte 1.15s — und das war der Ruckler.
     GEMESSEN (Trace, 1920x1080, 10 s):  mit Morph 134 Grossflaechen-Paints,
     ohne Morph 45. Chrome sagt den Grund selbst: compositeFailed 8192,
     unsupported:["--sorte"]. Eine VERERBTE Custom Property kann prinzipiell
     nicht auf den Compositor — Chrome muss sie im Main-Thread interpolieren und
     dabei 60x/s den GANZEN erbenden Subtree neu stylen: Text, Nav, alle 24
     img-Tags der Faecher. 1,15 s von 5,2 s, also 22 % der Zeit Rechenlast.
     Das Schweben selbst war nie schuld (Takt aus = 0,0 Mpx/s, 0 Paints).

     Jetzt springt --sorte hart (EIN Recalc) und statt der Property morphen ihre
     WIRKUNGEN einzeln: color/background-color/text-shadow transitionieren auf
     dem berechneten Wert und fassen nur ihre eigene Box an. Der Schein — die
     einzige grosse Flaeche — blendet als zwei Ebenen ueber opacity, und opacity
     IST compositor-faehig. Gleiche Dauer, gleiches Easing: optisch identisch. */
  --morph:.62s}

/* Der Schein haengt AN der Tafel (::before), nicht am Viewport-Rand. Am Rand
   aufgehaengt lag er auf einem 3440er Monitor 1300 px neben dem Macaron und
   leuchtete ins Leere — an die Tafel gekoppelt sitzt er auf jeder Breite richtig.
   Einzige Lichtquelle im Bild. Kein harter Farbblock: Dunkel bleibt dunkel,
   die Farbe bleibt als weicher Wash hinter dem Produkt sichtbar. */
/* Kein blur() — derselbe Fehler wie beim drop-shadow: ein Filter auf einem
   animierten Element wird Frame fuer Frame neu gerechnet. Und ein
   radial-gradient IST bereits weich; die 18px Blur darauf waren kaum zu sehen.
   Stattdessen ein zusaetzlicher Stop, der denselben weichen Auslauf umsonst
   liefert. will-change haelt den Schein auf einer eigenen GPU-Ebene. */
/* ZWEI Scheine statt einem: der sichtbare traegt die alte Farbe, der andere wird
   auf die neue gesetzt und blendet darueber. Jede Ebene liest --c (ihre EIGENE
   Farbe, von JS gesetzt) — nicht --sorte. Dadurch wird der 700px-Gradient beim
   Wechsel genau EINMAL gemalt statt 69-mal.
   Beide Ebenen tragen dieselbe Atem-Animation und starten gemeinsam, laufen also
   synchron — man sieht nie zwei versetzt pulsende Scheine. */
.tafel-schein{--c:#10D0E0;
  content:"";position:absolute;z-index:0;pointer-events:none;
  left:50%;top:46%;width:min(74vh,700px);aspect-ratio:1;
  background:radial-gradient(circle at 50% 50%,
    color-mix(in srgb,var(--c) 20%,transparent) 0%,
    color-mix(in srgb,var(--c) 13%,transparent) 26%,
    color-mix(in srgb,var(--c) 7%,transparent) 48%,
    color-mix(in srgb,var(--c) 2%,transparent) 62%,
    transparent 74%);
  opacity:0;
  transition:opacity var(--morph,1.15s) var(--ease-out);
  will-change:opacity,transform;
  animation:tafel-atem 7s ease-in-out infinite}
.tafel-schein.an{opacity:1}
/* translate3d statt translate: schiebt die Ebene auf die GPU, damit der Browser
   den fertigen Layer verschiebt statt ihn neu zu zeichnen. */
@keyframes tafel-atem{
  0%,100%{transform:translate3d(-50%,-50%,0) scale(1)}
  50%    {transform:translate3d(-50%,-50%,0) scale(1.07)}
}

/* Feines Korn — nimmt dem hellen Farbverlauf das Digitale. Auf dem hellen
   Grund deutlich niedriger dosiert; Inline-SVG, kein Extra-Request. */
.tafel-korn{position:absolute;inset:0;z-index:1;pointer-events:none;opacity:.18;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.32'/%3E%3C/svg%3E");
  /* Zum Heroende laeuft das Korn aus. So treffen Hero und helle Naht exakt
     aufeinander, auch wenn die Kornstaerke spaeter angepasst wird. */
  -webkit-mask-image:linear-gradient(to bottom,#000 78%,transparent 99%);
  mask-image:linear-gradient(to bottom,#000 78%,transparent 99%)}

/* ============ 1b · NAV AUF HELLEM HERO ============ */
/* pages.css schaltet auf der Startseite normalerweise die helle Logo-Fassung
   fuer einen dunklen Hero ein. Hier wird gezielt die dunkle Fassung
   zurueckgeholt; Layout und Scroll-Verhalten der Navigation bleiben gleich. */
.home .nav:not(.scrolled) .brand .logo-dunkel{opacity:1}
.home .nav:not(.scrolled) .brand .logo-hell{opacity:0}
.home .nav:not(.scrolled) .nav-links{color:var(--ink-soft)}
.home .nav:not(.scrolled) .nav-links a:hover,
.home .nav:not(.scrolled) .nav-links a.is-active{color:var(--sorte)}
.home .nav:not(.scrolled) .nav-cta{color:var(--sage-700);border-color:var(--sage-400)}
.home .nav:not(.scrolled) .nav-cta:hover{background:var(--sage-600);color:var(--on-sage);
  border-color:var(--sage-600)}
.home .nav:not(.scrolled) .nav-burger span,
.home .nav:not(.scrolled) .nav-burger span::before,
.home .nav:not(.scrolled) .nav-burger span::after{background:var(--sage-700)}

/* ============ 2 · COPY ============ */
.tafel-copy{position:relative;z-index:3;max-width:34rem;justify-self:start}
.tafel-eyebrow{display:inline-block;font-family:var(--font-body);font-weight:600;
  font-size:var(--fs-eyebrow);letter-spacing:.2em;text-transform:uppercase;
  color:var(--sorte);transition:color var(--morph,1.15s) var(--ease-out)}
.tafel-title{font-family:var(--font-display);color:var(--tafel-on);
  font-size:clamp(2.4rem,1.2rem + 3.6vw,4.4rem);line-height:1.04;letter-spacing:-.02em;
  margin-top:.7rem;text-wrap:balance}
/* Diese drei tragen den Farbwechsel im Text. Sie transitionieren den BERECHNETEN
   Wert (color/background-color/text-shadow) — Chrome fasst dabei nur ihre eigene
   Box an, statt wie bei --sorte den ganzen Subtree. */
.tafel-title em{font-style:italic;color:var(--sorte);
  transition:color var(--morph,1.15s) var(--ease-out)}
.tafel-lead{margin:1.1rem 0 0;color:var(--tafel-on-mute);font-weight:300;
  font-size:var(--fs-lead);line-height:1.6;text-wrap:pretty}
.tafel-lead strong{font-weight:500;color:var(--tafel-on)}
.tafel-fakt{margin:1rem 0 0;color:var(--tafel-on);font-weight:500;
  font-size:var(--fs-sm);letter-spacing:.02em}
.tafel-cta{display:flex;flex-wrap:wrap;gap:.8rem;margin-top:1.8rem}
/* Der Primaerbutton traegt den dunklen, auf Hell lesbaren Sortenakzent und
   morpht mit der Tafel. Porzellanfarbene Schrift haelt auf allen sechs
   Akzenten AA-Kontrast. */
.tafel-cta .btn-primary{background:var(--sorte);color:var(--porcelain);box-shadow:none;font-weight:600;
  transition:background-color var(--morph,1.15s) var(--ease-out)}
.tafel-cta .btn-primary:hover{background:color-mix(in srgb,var(--sorte) 88%,#000);color:var(--porcelain)}

/* ============ 3 · DIE TAFEL ============ */
/* --buehne-h und --schweb stehen HIER, weil zwei Dinge sie brauchen: die Buehne
   ihre Hoehe, und der Abstand zum Sortennamen die Amplitude.
   ⚠️ Der gap MUSS die Schwebe-Amplitude abdecken. Vorher stand hier feste
   1,2rem — das reichte fuer die alten ±2,8 %, aber seit ±6,5 % fuhr die Tafel
   im Tiefpunkt IN den Namen (gemessen: -18 px auf 1440, -50 px auf 4K, -15 px
   auf dem Handy). Ein fester Wert kann das nicht leisten: die Amplitude ist
   prozentual, waechst also mit der Buehne mit. Deshalb rechnet der gap mit
   demselben Faktor. Wer --schweb aendert, aendert den Abstand automatisch mit. */
.tafel{position:relative;z-index:2;justify-self:center;
  --buehne-h:clamp(300px,62svh,1040px);
  --schweb:.065;
  display:flex;flex-direction:column;align-items:center;
  gap:calc(var(--buehne-h) * var(--schweb) + .9rem)}
/* Ueber die HOEHE dimensioniert, nicht die Breite: der Hero ist hoehenbegrenzt
   (100svh), und der Stapel ist hochkant. So fuellt er die Buehne, statt in der
   Mitte zu schwimmen. */
/* z-index explizit: beide muessen ueber dem ::before-Schein liegen. */
.tafel-name,.tafel-buehne{position:relative;z-index:1}
/* Der alte Deckel von 600 px war fuer 1440er Schirme gedacht und wuergte die
   Tafel auf 4K auf 28 % der Fensterhoehe ab — ein verlorener Fleck in viel
   Schwarz. 1040 px halten auf 2160 px Hoehe rund 48 %, also dieselbe Wirkung
   wie 600 px auf 900 px. */
/* KEIN drop-shadow mehr — er war die Ruckelursache und dabei unsichtbar.
   Ein filter auf einem animierten Element zwingt den Browser, bei JEDEM Frame die
   Alphamaske des ganzen Inhalts (24 img-Tags) zu rastern und einen 46px-Blur
   darauf zu rechnen; auf 4K sind das 611.000 Pixel, 60-mal pro Sekunde.
   Gebracht hat er nichts: schwarzer Schatten auf fast schwarzem Grund
   (#0E1512) ergibt einen Helligkeitsunterschied von 0,004 — die
   Wahrnehmungsschwelle liegt bei etwa 0,005. Teuerster Effekt der Seite,
   fuer niemanden sichtbar. Die Abloesung vom Hintergrund leistet ohnehin der
   farbige Schein dahinter.

   will-change + translate3d halten die Buehne auf einer eigenen GPU-Ebene:
   der Browser rastert sie einmal und verschiebt danach nur noch den fertigen
   Layer, statt Frame fuer Frame neu zu zeichnen. */
.tafel-buehne{height:var(--buehne-h);aspect-ratio:848/1500;
  will-change:transform;
  animation:tafel-schweben 6.5s ease-in-out infinite}

/* Amplitude in PROZENT der eigenen Hoehe, nicht in px: der Weg waechst damit
   automatisch mit der Buehne mit. Ein fester px-Wert waere auf dem Handy
   Zappeln und auf 4K unsichtbar.

   ⚠️ WARUM ±6,5 % UND NICHT WENIGER — das ist keine Geschmacksfrage.
   Vorher standen hier ±2,8 % / 8,4 s. Gemessen (Screencast, echte
   Compositor-Frames, alles andere stillgelegt):

     ±2,8 % / 8,4 s ->   0 fps  (!)  Bild aendert sich 4 s lang NICHT
     ±5   % / 7   s ->  60 fps       5 % Standbild
     ±6,5 % / 6,5 s ->  60 fps       3 % Standbild   <- hier
     ±8   % / 6   s ->  60 fps       4 % Standbild

   Bei ±2,8 %/8,4 s bewegte sich die Tafel mit 0,155 px pro Frame — langsamer
   als ein Pixel je sechs Frames. Der Compositor rundet auf ganze Pixel, also
   war das Ergebnis buchstaeblich ein STANDBILD, das gelegentlich um 1 px
   ruckt. Genau das, was als "ruckelt" ankam: die Animation war nicht zu
   teuer, sie war zu LANGSAM. Faustregel: eine Schwebe-Animation braucht in
   der schnellsten Phase ~1 px/Frame, sonst rundet der Compositor sie tot.

   ⚠️ DAS ROTATE IST DER EIGENTLICHE TRICK — nicht Deko, sondern der Grund,
   warum es ueberhaupt fliesst. Selbst mit ±6,5 % kommt die Tafel nur auf
   0,646 px/Frame, bleibt also unter der 1-px-Schwelle; ein Schweben, das
   drueber kaeme, muesste hektisch schnell sein. Eine ROTATION kann der
   Compositor aber nicht aufs Pixelraster runden — er MUSS das Bild echt neu
   abtasten. Gemessen, gleiche Amplitude:

     nur translate        -> 60 fps,  4 % Standbild
     + rotate 0,35deg     -> 60 fps,  0 % Standbild   <- hier

   0,35deg sind an der Tafelkante keine 4 px. Man liest es nicht als Drehung,
   sondern als "haengt in der Luft" — und es kauft die Glaettung geschenkt.

   Der Schein atmet mit 7 s, die Tafel schwebt mit 6,5 s — bewusst teilerfremd
   (Gleichstand erst nach 91 s), damit die beiden Bewegungen nie in
   Gleichschritt fallen und das Bild nie "pumpt". */
/* Der Weg kommt aus --schweb (geerbt von .tafel), damit Amplitude und der gap
   zum Sortennamen NIE auseinanderlaufen koennen — beide lesen denselben Wert.
   Mobil setzt .tafel ihn auf .045 herunter, der Rest passt sich von selbst an. */
@keyframes tafel-schweben{
  0%,100%{transform:translate3d(0,calc(var(--schweb,.065) * -100%),0) rotate(-.35deg)}
  50%    {transform:translate3d(0,calc(var(--schweb,.065) * 100%),0) rotate(.35deg)}
}
.tafel-basis,.tafel-flaps{position:absolute;inset:0;width:100%;height:100%}
.tafel-basis{object-fit:contain;z-index:1}
.tafel-flaps{z-index:2}

/* Ein Fallblatt = ein waagerechtes Viertel. Es zeigt IMMER das ganze Bild und
   beschneidet nur die Sicht darauf (clip-path). Dadurch bleibt die Silhouette
   exakt zusammenhaengend — vier Bilder aneinanderzusetzen wuerde an jeder
   Bandgrenze eine sichtbare Kante erzeugen. */
.flap{position:absolute;inset:0;
  clip-path:inset(calc(var(--f) * 25%) 0 calc((3 - var(--f)) * 25%) 0)}
/* ⚠️ visibility ist hier KEIN Detail, sondern die halbe Startseite.
   Die Tafel haelt 24 img-Elemente (4 Baender x 6 Sorten), sichtbar sind immer
   nur 4. `opacity:0` nimmt ein Element aber NICHT aus dem Rendering — der
   Browser skalierte also bei jedem Rastern alle 24 Bilder von 848x1500 herunter,
   auch die 20 unsichtbaren. Gemessen: 35,5 Megapixel auf der Startseite, davon
   ~30 fuer die Tafel. `visibility:hidden` zeichnet nicht.
   Der Trick ist das transition-delay: beim EINblenden schaltet visibility sofort
   (0s), beim AUSblenden erst NACH der Blende — sonst verschwaende das Bild
   schlagartig statt zu faden. Der Bandversatz (--f * 105ms) muss in beiden
   Delays mitlaufen, sonst reisst die Kaskade. */
.flap img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  opacity:0;visibility:hidden;
  /* Der Versatz macht die Kaskade: Band 0 kippt, 70 ms spaeter Band 1 …
     Ohne ihn waere es ein simpler Crossfade. */
  transition:opacity .34s var(--ease-out) calc(var(--f) * 70ms),
             transform .34s var(--ease-out) calc(var(--f) * 70ms),
             visibility 0s linear calc(.34s + var(--f) * 70ms);
  transform:translateY(2.2%) scale(.985)}
.flap img.an{opacity:1;transform:none;visibility:visible;
  transition:opacity .34s var(--ease-out) calc(var(--f) * 70ms),
             transform .34s var(--ease-out) calc(var(--f) * 70ms),
             visibility 0s linear calc(var(--f) * 70ms)}

/* min-height fix in em: der laengste Name (Matchatee-Brombeere) darf die Tafel
   nicht hoeher schieben als der kuerzeste (Vanille) — sonst huepft der Stapel
   bei jedem Blaettern. */
/* Der Sortenname traegt die Farben der Sorte SELBST: ein Verlauf von --n1 nach
   --n2, per background-clip aufs Schriftbild geschnitten. Bei Doppelnamen faellt
   damit jeder Wortteil in seine eigene Farbe ("Pistazie" gruen -> "Himbeere"
   rosa), bei Einzelnamen sind beide Werte gleich und man sieht schlicht die
   Sortenfarbe. Kein zweites Markup noetig — ein span, ein Verlauf.
   Fraunces hat nur 400 und 500 (statische Schnitte, kein Bold), 500 ist also
   das Maximum ohne neue Schriftdatei; zusammen mit der Farbe traegt es genug.
   Der Glow laeuft ueber drop-shadow statt text-shadow: bei transparentem Text
   (color:transparent, noetig fuer background-clip) wuerde ein text-shadow
   DURCH die Buchstaben scheinen und den Namen zumatschen. drop-shadow legt
   sich um die sichtbare Form. Teuer ist es hier nicht — der Name steht still
   und animiert nur 0,24 s je Richtung beim Wechsel. */
.tafel-name{--n1:#087985;--n2:#087985;
  margin:0;font-family:var(--font-display);font-size:clamp(1.3rem,1rem + .85vw,2rem);
  font-weight:500;letter-spacing:.005em;min-height:1.7em;text-align:center;
  filter:drop-shadow(0 2px 10px rgba(34,39,31,.12))}
.tafel-name span{display:inline-block;
  background-image:linear-gradient(100deg,var(--n1) 8%,var(--n2) 92%);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;
  transition:opacity .24s var(--ease-out),transform .24s var(--ease-out)}
/* Ohne background-clip-Unterstuetzung bliebe der Name unsichtbar; hier faellt
   er auf die volle Leitfarbe zurueck. */
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .tafel-name span{color:var(--n1);background-image:none}
}
.tafel-name.wechselt span{opacity:0;transform:translateY(-.35em)}

/* ============ 3a · MOBIL: Tafel unten, Text oben ============ */
@media (max-width:899px){
  /* Die zweite Zeile bekommt 1fr: die Tafel nimmt exakt den Platz, der nach der
     Copy uebrig ist, statt auf eine feste Groesse zu bestehen und den Hero ueber
     die Falz zu schieben. Der Sortenname MUSS im Bild bleiben — ohne ihn ist das
     Blaettern nicht lesbar, sondern nur unruhig. */
  /* align-items MUSS hier von center auf stretch: sonst ist die .tafel nur so
     hoch wie ihr Inhalt, waehrend der Inhalt (flex-basis:0) seine Hoehe von der
     .tafel erwartet — beide warten aufeinander und die Buehne kollabiert auf 0. */
  /* ⚠️ Der gap trennt hier die Copy (mit den CTA-Buttons) von der Tafel — und
     die Tafel schwebt nach OBEN in genau diesen Spalt hinein. Vorher 1,5svh
     (~13 px), die Amplitude war ±17 px: gemessen -5 px auf iPhone 390, -4 auf
     375, -3 auf Android 360 — die Macarons berührten "Alle 17 Sorten".
     max(22px, …) statt reiner svh: auf flachen Geräten schrumpft svh weg,
     die Amplitude aber nicht (sie hängt an der Bühnenhöhe, nicht am Fenster). */
  .tafel-hero{grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr);
    align-items:stretch;align-content:stretch;
    gap:max(22px,2.6svh);padding-top:calc(var(--nav-h) + 2.5svh);padding-bottom:3svh}
  .tafel-copy{max-width:none}
  /* Der vierzeilige Lead drueckt die Tafel aus dem Bild -> auf dem Handy raus.
     Er traegt nichts, was der Body gleich darunter nicht erzaehlt; die
     Handelszeile (Preis/Abholung) bleibt — das ist, was gesucht wird. */
  .tafel-lead{display:none}
  .tafel-cta{margin-top:1.1rem;gap:.6rem;flex-wrap:nowrap}
  /* btn-lg (1.05em/2.3em) sprengt zwei Buttons nebeneinander auf 375px und
     zwingt sie untereinander — das kostet 60 px Hoehe, die die Tafel braucht. */
  .tafel-cta .btn{padding:.85em 1.35em;font-size:.95rem;flex:1 1 0;text-align:center}
  .tafel-title{font-size:clamp(2rem,1.3rem + 4vw,2.8rem)}
  /* Hier kann der gap NICHT mit --buehne-h rechnen: die Buehne bekommt ihre
     Hoehe unten per flex:1 1 0 zugeteilt, --buehne-h gilt nur am Desktop.
     Also fester Wert — er muss die Amplitude auf der groesstmoeglichen mobilen
     Buehne abdecken (max-width 240px / aspect 848:1500 -> ~425px hoch,
     ±4,5 % = 19 px). 1,9rem = 30 px lassen 11 px Luft.
     Amplitude hier bewusst kleiner als am Desktop: auf einem 400-px-Bild wirken
     ±6,5 % unruhig, und jeder Pixel gap geht der Buehne ab. Die Glaettung traegt
     ohnehin das rotate, nicht der Weg (auf dem Handy gemessen: 0 % Standbild).
     .035 statt .045: die Tafel muss auf dem Handy nach OBEN gegen die CTA-Buttons
     und nach UNTEN gegen den Sortennamen Platz halten — jeder Prozentpunkt
     Amplitude kostet zweimal Luft, und Luft ist hier das Knappste. */
  .tafel{min-height:0;justify-content:center;--schweb:.035;gap:1.9rem}
  /* flex:1 1 0 + min-height:0 -> die Buehne bekommt die Resthoehe zugeteilt und
     leitet ihre Breite aus dem aspect-ratio ab. height:auto allein waere 0: die
     Faecher sind absolut positioniert, es gibt nichts, was von innen Hoehe gaebe. */
  .tafel-buehne{height:auto;width:auto;flex:1 1 0;min-height:0;max-width:min(52vw,240px)}
  .tafel-name{font-size:1.05rem;min-height:1.5em}
  .tafel::before{width:min(56vh,430px)}
}
/* Sehr flache Handys: Eyebrow raus. H1 + Handelszeile + CTAs bleiben IMMER. */
@media (max-height:680px) and (max-width:899px){
  .tafel-eyebrow{display:none}
  .tafel-title{font-size:clamp(1.8rem,1.2rem + 3.2vw,2.4rem)}
  .tafel-buehne{max-width:min(38vw,170px)}
}

/* ============ 3c · SEHR GROSSE SCHIRME (4K & Co.) ============ */
/* Die Basis-clamps sind bei ~1440px am Anschlag und wachsen nicht weiter — auf
   einem 3840er Schirm schrumpft der Hero dadurch optisch zu einer Briefmarke in
   viel Schwarz. Alles hier hebt nur die DECKEL an; unter 2000px aendert sich
   nichts.
   An die HOEHE mitgekoppelt (min-height): ein breiter, aber flacher Schirm
   (3440x1080) hat nicht mehr Platz fuer Typo, nur mehr Breite — dort waere
   groesser falsch. */
@media (min-width:2000px) and (min-height:1200px){
  .tafel-hero{padding-inline:max(var(--edge),calc((100% - 1900px) / 2))}
  /* 52rem, damit "Siebzehn Sorten." bei 105 px Schriftgrad auf EINER Zeile
     bleibt — der eingebaute <br> setzt den Umbruch, nicht der Zufall. */
  .tafel-copy{max-width:52rem}
  .tafel-eyebrow{font-size:1rem;letter-spacing:.22em}
  .tafel-title{font-size:clamp(4.4rem,3.4vw,6.6rem)}
  /* Der Lead darf NICHT mit: 52rem waeren ~85 Zeichen pro Zeile, unlesbar. */
  .tafel-lead{font-size:1.35rem;line-height:1.62;max-width:34rem}
  .tafel-fakt{font-size:1.15rem}
  .tafel-cta{gap:1.1rem;margin-top:2.4rem}
  .tafel-cta .btn{font-size:1.2rem;padding:1.1em 2.6em}
  .tafel-name{font-size:2.1rem}
}

/* ============ 3b · REDUCED-MOTION ============ */
/* Alles Bewegte still: kein Blaettern (home.js startet den Takt gar nicht
   erst), kein Schweben, kein Atmen. Uebrig bleibt ein ruhiges Standbild mit
   farbigem Schein — es geht KEINE Information verloren, die Tafel traegt
   keine, die nicht als Text danebensteht. */
@media (prefers-reduced-motion: reduce){
  /* will-change mit raus: ohne Animation waere die GPU-Ebene nur verschenkter
     Speicher. */
  .tafel-buehne,.tafel-schein{animation:none;will-change:auto}
  .tafel-schein{transform:translate3d(-50%,-50%,0)}   /* die Keyframes trugen es sonst */
  .flap img,.flap img.an{transition:none}
}

/* ============ 4 · HELLE NAHT (Tafel → Porzellan) ============ */
/* Der Hero endet bereits fast auf Porzellan. Eine kurze, helle Rampe behaelt
   den weichen Abschnittswechsel, ohne den frueher noetigen langen Dunkel→Hell-
   Uebergang oder einen sichtbaren Farbsprung. */
.cine-seam{height:clamp(64px,8vh,120px);
  background:linear-gradient(180deg,var(--tafel-bg-bot) 0%,var(--porcelain) 100%)}
.cine-seam{background:linear-gradient(180deg in oklab,
    var(--tafel-bg-bot) 0%,var(--porcelain) 100%)}

/* ============ 5 · HELLER BODY — TEASER-MODULE ============ */

/* 5.1 Marken-Statement */
.home-intro{text-align:center}
.home-intro .wrap{max-width:var(--wrap-narrow)}
.home-intro .statement{font-family:var(--font-display);font-size:var(--fs-h2);
  line-height:1.22;color:var(--sage-700);letter-spacing:-.01em;margin:.6rem auto 0;max-width:26ch;text-wrap:balance}
.home-intro .statement em{font-style:italic;color:var(--gold-deep)}
.home-intro .lead{margin:1.3rem auto 0}

/* 5.2 MACARONS — der Star */
.star{position:relative;overflow:hidden}
.star .wrap{max-width:var(--wrap-wide)}
.star-head{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;
  gap:1.4rem;margin-bottom:clamp(1.8rem,3vw,2.8rem)}
.star-head .txt{max-width:36ch}
.star-head h2{margin-top:.5rem}
.star-head .price-badge{display:inline-flex;align-items:center;gap:.5rem;
  padding:.55em 1.1em;border:1px solid var(--gold);border-radius:var(--r-pill);
  color:var(--gold-deep);font-weight:600;font-size:.95rem;font-variant-numeric:tabular-nums;white-space:nowrap}
.star-head .price-badge::before{content:"";width:9px;height:9px;border-radius:50%;background:var(--rose)}

.mac-strip{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:clamp(.7rem,1.4vw,1.2rem)}
.mac-strip>*{min-width:0}
.mac-card{position:relative;border-radius:var(--r-card);overflow:hidden;background:var(--paper);
  border:1px solid var(--hairline);box-shadow:var(--sh-sm);
  transition:transform var(--dur) var(--ease-out),box-shadow var(--dur) var(--ease-out),border-color var(--dur) var(--ease-out)}
.mac-card .ph{aspect-ratio:1/1;overflow:hidden;
  background:radial-gradient(120% 90% at 50% 30%,var(--flavor-wash,var(--sage-wash)),var(--paper) 80%)}
.mac-card img{width:100%;height:100%;object-fit:cover;transition:transform var(--dur-slow) var(--ease-out)}
.mac-card .cap{display:flex;align-items:center;gap:.42rem;padding:.7rem .8rem .8rem;
  font-family:var(--font-display);font-size:.98rem;color:var(--sage-700);line-height:1.15}
.mac-card .cap::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--flavor,var(--sage-500));flex:0 0 auto}
.mac-card:hover{transform:translateY(-6px);box-shadow:var(--sh-lg);border-color:var(--hairline-sage)}
.mac-card:hover img{transform:scale(1.06)}
.star-foot{margin-top:clamp(1.8rem,3vw,2.6rem);display:flex;flex-wrap:wrap;gap:1rem;align-items:center;justify-content:center}

/* 5.3 TÖRTCHEN & TORTEN — Split */
.duo{display:grid;grid-template-columns:1.05fr 1fr;gap:clamp(1.8rem,4vw,4rem);align-items:center}
.duo>*{min-width:0}
.duo .duo-media{position:relative;border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--sh-lg);aspect-ratio:4/3}
.duo .duo-media img{width:100%;height:100%;object-fit:cover}
.duo .duo-media .frame{position:absolute;inset:.7rem;border:1px solid rgba(180,138,74,.5);
  border-radius:calc(var(--r-lg) - 6px);pointer-events:none}
.duo .duo-media .tag{position:absolute;left:1rem;bottom:1rem;background:rgba(28,39,26,.72);
  color:var(--on-sage);font-size:.8rem;padding:.4em .9em;border-radius:var(--r-pill);backdrop-filter:blur(4px)}
.duo h2{margin-top:.5rem}
.duo .price{display:inline-block;margin:.3rem 0 .1rem}
.duo .duo-list{list-style:none;margin:1.2rem 0 1.6rem;display:flex;flex-direction:column;gap:.7rem}
.duo .duo-list li{position:relative;padding-left:1.5rem;color:var(--ink-soft);font-weight:300}
.duo .duo-list li::before{content:"";position:absolute;left:0;top:.55em;width:12px;height:1px;background:var(--gold)}
.duo .duo-cta{display:flex;flex-wrap:wrap;gap:.8rem}

/* 5.4 ANLÄSSE — Portfolio-Teaser (3 GLEICH GROSSE Fotos) */
.occ .occ-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(.8rem,1.5vw,1.2rem);
  grid-auto-rows:1fr}
.occ .occ-grid>*{min-width:0}
.occ .occ-tile{position:relative;border-radius:var(--r);overflow:hidden;aspect-ratio:3/4;box-shadow:var(--sh)}
.occ .occ-tile img{width:100%;height:100%;object-fit:cover;transition:transform var(--dur-slow) var(--ease-out)}
.occ .occ-tile:hover img{transform:scale(1.05)}
.occ .occ-tile .lab{position:absolute;left:0;right:0;bottom:0;padding:1.1rem .9rem .8rem;color:#fff;
  font-size:.9rem;background:linear-gradient(180deg,transparent,rgba(28,39,26,.74))}

/* 5.5 BESUCH / NAP-Streifen */
.visit .visit-card{display:grid;grid-template-columns:1.1fr 1fr;gap:clamp(1.6rem,4vw,3.5rem);
  align-items:center;background:var(--paper);border:1px solid var(--hairline);
  border-radius:var(--r-lg);padding:clamp(1.6rem,3vw,2.8rem);box-shadow:var(--sh)}
.visit .visit-card>*{min-width:0}
.visit .nap-line{display:flex;gap:.8rem;align-items:baseline;padding:.55rem 0;border-bottom:1px solid var(--hairline)}
.visit .nap-line:last-of-type{border-bottom:0}
.visit .nap-line .k{flex:0 0 6.5rem;color:var(--ink-mute);font-size:.85rem;letter-spacing:.04em;text-transform:uppercase}
.visit .nap-line .v{color:var(--ink);font-weight:400}
.visit .nap-line .v a{color:var(--sage-700);text-decoration:underline;text-underline-offset:3px;text-decoration-color:var(--gold)}
.visit .visit-cta{margin-top:1.4rem;display:flex;flex-wrap:wrap;gap:.8rem}

/* ============ 6 · RESPONSIVE ============ */
@media (max-width:1024px){
  .mac-strip{grid-template-columns:repeat(3,minmax(0,1fr))}
  .duo{grid-template-columns:1fr;gap:2rem}
  .duo .duo-media{aspect-ratio:16/10;order:-1}
  .occ .occ-grid{grid-template-columns:repeat(3,minmax(0,1fr))}
  .visit .visit-card{grid-template-columns:1fr}
}
@media (max-width:640px){
  .mac-strip{grid-template-columns:repeat(2,minmax(0,1fr))}
  .star-head{flex-direction:column;align-items:flex-start}
  /* Anlass-Kacheln: gestapelt, ALLE gleich groß (kein Sonderfall) */
  .occ .occ-grid{grid-template-columns:1fr;gap:1rem;max-width:420px;margin-inline:auto}
  .occ .occ-tile{aspect-ratio:16/10}
  .visit .nap-line{flex-direction:column;gap:.15rem}
  .visit .nap-line .k{flex-basis:auto}
}
@media (max-width:760px){
  .bruch-eyebrow{font-size:.66rem;letter-spacing:.18em}
  .bruch-cta .btn{padding:.8em 1.4em;font-size:.95rem}
}
@media (min-width:2200px){
  .star .wrap,.occ .wrap{max-width:1680px}
}

/* Reveal-Startzustand (IO togglet .in; JS in home.js) */
.reveal{opacity:0;transform:translateY(22px);
  transition:opacity var(--dur-slow) var(--ease-out),transform var(--dur-slow) var(--ease-out);
  transition-delay:calc(var(--i,0) * 80ms)}
.reveal.in{opacity:1;transform:none}
@media (prefers-reduced-motion: reduce){
  .reveal{opacity:1;transform:none;transition:none}
}
