{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "speisekarte-editorial",
 "name": "Speisekarte als Editorial",
 "name_en": "Editorial menu with tabs, tabular prices and allergen legend",
 "kurz": "Karte als HTML-Text mit Rubriken-Tabs, Preisen in Tabellenziffern, Allergen-Kürzeln mit verankerter Erklärung, Filter nach Verträglichkeit und Druckversion.",
 "kategorie": "Sektionen & Funktionen",
 "kategorie_slug": "sektionen",
 "kategorie_nr": 16,
 "bau_chat": "D",
 "prioritaet": "D",
 "trendstatus": "etabliert",
 "belegstatus": "teilbelegt",
 "website_belege": 1,
 "stimmung": [
  "editorial",
  "präzise",
  "warm"
 ],
 "stimmung_roh": [
  "warm",
  "editorial",
  "funktional"
 ],
 "technik": [
  "css",
  "vanilla-js",
  "popover",
  "anchor-positioning"
 ],
 "technik_gruppen": [
  "css",
  "js"
 ],
 "leistungskosten": "niedrig",
 "steckbrief": {
  "beschreibung": "Die Karte steht als echter HTML-Text auf der Seite, nicht als PDF. Rubriken-Tabs wechseln zwischen Mittag, Abend und Getränken. Gerichte stehen in einer ruhigen Liste: Name, kurze Beschreibung, Preis rechtsbündig mit Tabellenziffern, damit die Kommastellen untereinander stehen. Allergene und Kennzeichnungen erscheinen als Kürzel. Ein Klick auf ein Kürzel öffnet eine kurze Erklärung; eine Legende steht zusätzlich unter der Karte. Eine Druckversion zeigt alle Rubriken untereinander. Trennlinien kommen 2026 per Gap Decorations (row-rule) und fallen in älteren Browsern auf einfache Rahmen zurück.",
  "warum_es_wirkt": "Gäste suchen auf dem Telefon schnell nach Preis und Unverträglichkeiten. Text ist lesbar, durchsuchbar, übersetzbar und für Suchmaschinen sichtbar. Tabellenziffern geben der Preisspalte Ruhe, die Serif der Gerichte gibt Charakter. Die Karte wirkt wie gedruckt und bleibt trotzdem bedienbar.",
  "wann_einsetzen": "Restaurant, Bistro, Café, Bar, Hotelrestaurant, Kantine; auch für Preislisten mit wenigen Rubriken (Friseur, Kosmetik, Werkstatt-Pauschalen).",
  "wann_nicht": "Bei sehr großen Karten mit Dutzenden Rubriken (dann Sprungliste statt Tabs). Wenn sich die Karte täglich ändert und niemand sie pflegt: dann lieber eine Tageskarte mit Datum als eine veraltete Hauptkarte.",
  "varianten": [
   "Bistro-Tafel: dichte Liste mit Rubriken-Tabs, Tagesgericht hervorgehoben",
   "Fine-Dining-Menü: Gänge zentriert untereinander, Menüpreis und Weinbegleitung als eigene Zeile",
   "Preisliste Dienstleistung (Friseur, Kosmetik, Kfz-Werkstatt): Leistung, Dauer und ab-Preis nach Haarlänge oder Fahrzeugklasse, Stufe wählbar, „Endpreis nach Beratung“",
   "Mehrere Karten als Sprungliste statt Tabs, wenn es mehr als vier Rubriken gibt"
  ],
  "umsetzung": "Markup: Tabs mit role=tablist, tab und tabpanel (Pfeiltasten, Home, End). In jedem Panel Rubriken als section mit h3 und ul; jedes Gericht als li mit h4, Preis als <data value=\"14.20\">14,20</data> und einem Kürzel-Knopf. Preise: font-variant-numeric: tabular-nums lining-nums, rechtsbündig, Währung einmal im Kopf. Kürzel: ein button je Gericht mit aria-label \"Allergene: Gluten, Eier, Milch\", aria-expanded und aria-controls; ein gemeinsames Popover (popover=auto) wird per JS gefüllt und mit showPopover({ source: knopf }) geöffnet. Der offene Knopf trägt anchor-name: --kz, das Popover sitzt mit position-anchor: --kz; top: anchor(bottom); right: anchor(right) und weicht per position-try-fallbacks nach oben oder links aus. Ohne Anchor Positioning rechnet JS die Lage aus getBoundingClientRect. Linien: @supports bzw. CSS.supports('row-rule: 1px solid red') → .gerichte { row-gap: 28px; row-rule: 1px dotted … }, .rubriken { column-rule: 1px solid … }; sonst border-top an jedem sichtbaren Gericht ab dem zweiten. Filter: aria-pressed-Knöpfe blenden Gerichte per hidden aus, zählen live (aria-live=polite) und zeigen je Rubrik einen Leerzustand. Druck: @media print zeigt alle Panels mit Titel aus data-titel und blendet Tabs, Filter und Popover aus. Die Legende steht immer als Text unter der Karte. Strukturierte Daten (schema.org Menu, MenuSection, MenuItem) lassen sich ergänzen.",
  "mobil": "Eine Spalte, Tabs kleben beim Scrollen oben. Kürzel-Knöpfe mindestens 30 px hoch, Erklärung per Tippen. Der Druck-Knopf entfällt auf schmalen Bildschirmen.",
  "reduzierte_bewegung": "Tabs und Erklärungen wechseln ohne Übergang.",
  "barrierefreiheit": "Tabs nach dem APG-Muster mit Pfeiltasten, Home und End; das Panel ist fokussierbar. Kürzel-Knöpfe haben den vollen Namen als zugänglichen Namen, die Information steckt also nicht nur im Popover; die Legende steht zusätzlich als Text unter der Karte. Kennzeichen V und VG sind abbr mit title. Trefferzahl des Filters in einer aria-live-Region, Leerzustand als Text. Kontrast Text 10:1, leiser Text 4,6:1 auf #f0ece0. Allergenkennzeichnung und Preisangaben in Inhalt und Form vom Kunden prüfen lassen."
 },
 "messwerte": {
  "easing": "cubic-bezier(0.16, 1, 0.3, 1)",
  "dauer_ms": "200 (Tabs, Popover), 700 (Bilder)",
  "stagger_ms": "",
  "distanz": "Popover 6 px Weg",
  "sonstiges": "Gericht 1.125rem/500, Beschreibung 0.9375rem, Preis rechtsbündig mit Tabellenziffern (Rezept gastro-warm-appetitlich)",
  "herkunft": "eigene Festlegung",
  "quelle": "Rezept gastro-warm-appetitlich (bewegung, schrift.groessen)"
 },
 "kurve": {
  "bezier": [
   0.16,
   1.0,
   0.3,
   1.0
  ],
  "css": "cubic-bezier(0.16, 1, 0.3, 1)",
  "name": "expo.out",
  "dauer_ms": 200
 },
 "gesehen_bei": [
  {
   "seite": "Dishoom: All Day Menu",
   "url": "https://dishoom.com/menu/all-day-main",
   "auszeichnung": "",
   "beobachtung": "Per WebFetch am 01.11.2026 gelesen: Karte als HTML-Text, jedes Gericht als Überschrift mit Preis ohne Währungszeichen, Beschreibung darunter. Kürzel (S), (V), (Ve) am Ende der Beschreibung, Legende auf der Seite: „(S) Spicy (V) Suitable for vegetarians (Ve) Suitable for vegans“. Weitere Karten (Breakfast, Drinks) als eigene Seiten verlinkt.",
   "art": "website"
  },
  {
   "seite": "Chrome Developers: Gap decorations stable",
   "url": "https://developer.chrome.com/blog/gap-decorations-stable",
   "auszeichnung": "",
   "beobachtung": "Gap Decorations sind seit Chrome und Edge 149 ohne Flag aktiv: column-rule und row-rule für Grid, Flex und Mehrspalten, dazu rule-break, rule-inset und rule-visibility-items. Der Artikel empfiehlt sie als progressive Verbesserung, ältere Browser zeigen die Lücke ohne Linie.",
   "art": "artikel"
  },
  {
   "seite": "Inclusive Components: Tooltips & Toggletips",
   "url": "https://inclusive-components.design/tooltips-toggletips/",
   "auszeichnung": "",
   "beobachtung": "Toggletip als echter button type=button; die Erklärung erscheint erst nach dem Klick in einem role=status-Bereich, Escape und Klick daneben schließen. Kein aria-describedby, sonst hört man die Erklärung schon vorher.",
   "art": "artikel"
  }
 ],
 "tutorials": [
  {
   "titel": "Chrome: Gap decorations stable",
   "url": "https://developer.chrome.com/blog/gap-decorations-stable"
  },
  {
   "titel": "MDN: font-variant-numeric",
   "url": "https://developer.mozilla.org/docs/Web/CSS/font-variant-numeric"
  },
  {
   "titel": "Inclusive Components: Tooltips & Toggletips",
   "url": "https://inclusive-components.design/tooltips-toggletips/"
  }
 ],
 "kombinierbar_mit": [
  "gleitender-indikator",
  "tabellenziffern",
  "papier-druck-textur",
  "native-popover-dropdowns",
  "serif-grotesk-duotone",
  "mobile-bottom-navigation"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/sektionen/speisekarte-editorial/",
  "meta": "https://cecodesign.de/lab/fundus/sektionen/speisekarte-editorial/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/sektionen/speisekarte-editorial/demo"
 },
 "herkunft": {
  "quelldateien": [
   "DEF-Recherche 01.11.2026"
  ],
  "pruefnotizen": [
   "Dishoom-Karte per WebFetch am 01.11.2026 gelesen (Struktur, Kürzel, Legende). Gap Decorations laut Chrome-Blog ab Chrome/Edge 149.",
   "Allergenkennzeichnung (14 Hauptallergene nach LMIV) und Preisangaben sind Pflichtthemen in der Gastronomie: Inhalt und Form vom Kunden prüfen lassen."
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Karte als HTML-Text mit Rubriken-Tabs, Preisen in Tabellenziffern, Allergen-Kürzeln mit verankerter Erklärung, Filter nach Verträglichkeit und Druckversion.",
  "demo": true,
  "abhaengigkeiten": [],
  "werte": {
   "easing": "cubic-bezier(0.16, 1, 0.3, 1) (expo.out, Rezept gastro-warm-appetitlich)",
   "dauer_ms": 200,
   "dauer_ms_hinweis": "Tab-Unterstrich (left/right per Anchor Positioning), Panel-Einblendung, Popover, Filter-Chips",
   "panel_einblendung": "opacity 0 → 1, translate 0 6px → 0, 200 ms",
   "popover": "opacity 0 → 1, translate 0 -6px → 0, 200 ms, @starting-style, Exit mit overlay/display allow-discrete; Lage top: anchor(bottom), right: anchor(right), 8 px Abstand, Ausweichen nach oben (@position-try --oben) und links",
   "farbwechsel_variante_ms": 400,
   "schrift": "Fraunces (Titel 430, SOFT 100; Gericht 1.125rem/500, SOFT 50, opsz 24; Rubrik kursiv 380 1.5rem), Commissioner (Text 1.0625rem/1.55, Beschreibung 0.9375rem, Label 0.75rem FLAR 80, Laufweite 0.15em)",
   "preise": "font-variant-numeric: tabular-nums lining-nums, rechtsbündig, ohne Euro-Zeichen; Währung einmal im Kopf (in Euro inkl. MwSt.); <data value=\"14.20\">",
   "linien_gap_decorations": "Gerichte row-gap 28px, row-rule 1px dotted rgba(53,56,57,.34); Rubriken column-rule 1px solid rgba(53,56,57,.16); Legende column-rule und row-rule, rule-visibility-items: between",
   "linien_fallback": "ohne row-rule: row-gap 14px, border-top 1px dotted an jedem sichtbaren Gericht ab dem zweiten (.g:not([hidden]) ~ .g:not([hidden])), border-left an der Hauptrubrik",
   "erkennung": "CSS.supports('row-rule: 1px solid red') setzt .gd am html",
   "spalten": "Container Query karte ≥ 640px: zwei Spalten, die größte Rubrik (Warm, Hauptgang) rechts über drei Zeilen (auto auto 1fr), bei vier Rubriken 2 × 2",
   "kuerzel_knopf": "min-height 26px (Touch 30px), Radius 999px, 0.6875rem/600, Laufweite 0.06em; aria-expanded true trägt anchor-name: --kz",
   "farben": "Grund #f0ece0, Text #353839, leise #6b6a62, Salbei-tief #4f6a4b (Rubriken, Kennzeichen), Senf #eac16e (Reservieren, Häkchen), Dunkel #293e3a (Popover, gewählter Chip)",
   "druck": "@media print: alle Panels untereinander mit Titel aus data-titel, Filter ignoriert, Tabs, Chips, Kopf und Popover aus, Schrift 12px, @page 14mm 16mm",
   "vorfuehrung_runde_ms": "12800 (Bistro), 10800 (Fine Dining)"
  },
  "ausloeser": "klick",
  "touch": "Kürzel-Knöpfe wachsen auf 30 px Höhe, die Erklärung öffnet per Tippen und schließt per ×, Tippen daneben oder Zurück-Taste (popover=auto). Ab 860 px Breite abwärts eine Spalte, die Tabs bleiben beim Scrollen oben kleben. Der Druck-Knopf entfällt unter 560 px.",
  "reduziert": "Alle Übergänge aus: Unterstrich springt, Panels und Popover erscheinen ohne Einblendung, Variantenwechsel ohne Farbübergang.",
  "korrekturen": {
   "umsetzung": "Markup: Tabs mit role=tablist, tab und tabpanel (Pfeiltasten, Home, End). In jedem Panel Rubriken als section mit h3 und ul; jedes Gericht als li mit h4, Preis als <data value=\"14.20\">14,20</data> und einem Kürzel-Knopf. Preise: font-variant-numeric: tabular-nums lining-nums, rechtsbündig, Währung einmal im Kopf. Kürzel: ein button je Gericht mit aria-label \"Allergene: Gluten, Eier, Milch\", aria-expanded und aria-controls; ein gemeinsames Popover (popover=auto) wird per JS gefüllt und mit showPopover({ source: knopf }) geöffnet. Der offene Knopf trägt anchor-name: --kz, das Popover sitzt mit position-anchor: --kz; top: anchor(bottom); right: anchor(right) und weicht per position-try-fallbacks nach oben oder links aus. Ohne Anchor Positioning rechnet JS die Lage aus getBoundingClientRect. Linien: @supports bzw. CSS.supports('row-rule: 1px solid red') → .gerichte { row-gap: 28px; row-rule: 1px dotted … }, .rubriken { column-rule: 1px solid … }; sonst border-top an jedem sichtbaren Gericht ab dem zweiten. Filter: aria-pressed-Knöpfe blenden Gerichte per hidden aus, zählen live (aria-live=polite) und zeigen je Rubrik einen Leerzustand. Druck: @media print zeigt alle Panels mit Titel aus data-titel und blendet Tabs, Filter und Popover aus. Die Legende steht immer als Text unter der Karte. Strukturierte Daten (schema.org Menu, MenuSection, MenuItem) lassen sich ergänzen.",
   "barrierefreiheit": "Tabs nach dem APG-Muster mit Pfeiltasten, Home und End; das Panel ist fokussierbar. Kürzel-Knöpfe haben den vollen Namen als zugänglichen Namen, die Information steckt also nicht nur im Popover; die Legende steht zusätzlich als Text unter der Karte. Kennzeichen V und VG sind abbr mit title. Trefferzahl des Filters in einer aria-live-Region, Leerzustand als Text. Kontrast Text 10:1, leiser Text 4,6:1 auf #f0ece0. Allergenkennzeichnung und Preisangaben in Inhalt und Form vom Kunden prüfen lassen.",
   "mobil": "Eine Spalte, Tabs kleben beim Scrollen oben. Kürzel-Knöpfe mindestens 30 px hoch, Erklärung per Tippen. Der Druck-Knopf entfällt auf schmalen Bildschirmen."
  },
  "geprueft": "02.11.2026",
  "notiz": "Welt: Rezept gastro-warm-appetitlich, erfundenes Bistro Rotmain in Bayreuth (Bistro & Weinstube, abends die Stube mit Menü). Fraunces und Commissioner, Papier-Weiß #f0ece0, Salbei, Senf nur für Reservieren und Häkchen. Fränkische Herbstkarte mit 34 Gerichten und Getränken, 14 Hauptallergene als Buchstaben A bis N mit Legende. Pult: Variante Bistro-Tafel oder Fine-Dining-Menü (?v=bistro|menue), Linien per Gap Decorations oder Fallback (sieht absichtlich fast gleich aus), Druckansicht als A4-Blatt am Bildschirm (dieselben Regeln wie @media print). Vorführung: Zeiger wechselt auf Abend, öffnet die Erklärung am Schäufele, setzt ohne Gluten und vegetarisch (Hauptgang wird leer), wechselt durch die Tabs. Keine Bilder: Gerichte ohne Foto, damit die Karte als Baustein neben echten Food-Fotos steht. Referenzen: dishoom.com (Kürzel-Legende), developer.chrome.com (Gap Decorations), inclusive-components.design (Toggletip). AD-Review 02.11.2026: Note 5. Zugang 02.11.2026: Reiter unter 360 px kleiner und mit Silbentrennung (kein Querscrollen bei 320 px), Kontrastmodus: Knopfrahmen und Highlight-Outline am gewählten Reiter. „Klickbar, nicht fokussierbar“ ist kein Fehler: Reiter mit wanderndem tabindex (Pfeiltasten). Korrektur 02.11.2026: Variante „Preisliste Dienstleistung“ (preisliste) für Salon und Werkstatt in der Welt von friseur-salon-handschrift (Salon Kammzug, Regensburg): Reiter Damen, Herren, Farbe, Pflege; Tabelle Leistung, Dauer, Preis je Haarlänge, Stufe Junior/Stylist/Master wählbar, ab-Preise mit Popover „wovon er abhängt“ und „Endpreis nach Beratung“; Druckansicht und Popover der Grundvariante weiterverwendet. Kalnia und Familjen Grotesk neu in assets/fonts (OFL, aus google/fonts als Latin-woff2 erzeugt, da npm und jsDelivr hier gesperrt waren). Geprüft: pruef.sh --v preisliste, zugang regeln/breite320 ohne Befund.",
  "varianten": [
   {
    "id": "bistro",
    "name": "Bistro-Tafel",
    "wann": "Bistro, Wirtshaus, Café, Bar und Mittagstisch: viele Gerichte, Rubriken-Tabs nach Tageszeit, Filter nach Verträglichkeit.",
    "werte": {
     "grund": "#f0ece0",
     "layout": "Einleitung links sticky (4fr), Karte rechts (8.4fr), Rubriken zweispaltig",
     "tabs": "Mittag · Abend · Getränke mit Zeiten und Trefferzahl",
     "filter": "vegetarisch, ohne Gluten (A), ohne Milch (G); Leerzustand je Rubrik"
    },
    "knopf": "Bistro-Tafel"
   },
   {
    "id": "menue",
    "name": "Fine-Dining-Menü",
    "wann": "Gehobene Küche, Hotelrestaurant, Stube mit festem Menü: wenige Gänge, viel Raum, Menüpreis und Begleitung als eigene Zeilen.",
    "werte": {
     "grund": "#293e3a",
     "text": "#f0ece0",
     "akzent": "#e1c48f",
     "layout": "eine Spalte, max. 820px, Einleitung zentriert",
     "gang": "Fraunces 330, clamp(1.75rem, 1.3rem + 1.4vw, 2.5rem), SOFT 0, opsz 144; römische Ziffer kursiv; row-gap 44px mit row-rule 1px solid",
     "tabs": "Herbstmenü · Pflanzlich · Begleitung",
     "filter": "entfällt, Hinweis auf Unverträglichkeiten bei der Reservierung",
     "popover": "hell (#f0ece0 auf #293e3a umgekehrt)"
    },
    "knopf": "Fine Dining"
   },
   {
    "id": "preisliste",
    "name": "Preisliste Dienstleistung",
    "knopf": "Salon-Preise",
    "wann": "Friseur, Barbershop, Kosmetik, Nagelstudio, auch Kfz-Werkstatt (Spalten dann nach Fahrzeugklasse statt Haarlänge): Leistung, Dauer und ab-Preis je Zeile als echte HTML-Tabelle, Stufe (bei wem) und Haarlänge wählbar, „ab“ immer mit dem Satz „Endpreis nach Beratung“ und wovon er abhängt. Welt des Rezepts friseur-salon-handschrift.",
    "werte": {
     "rezept": "friseur-salon-handschrift (Salon Kammzug, Regensburg)",
     "schrift": "Kalnia (wdth 100–125, wght 100–700) für Salonname 600/wdth 125, h1 500/wdth 112 clamp(2.375rem, 1.3rem + 2.6vw, 3.75rem)/0.98 mit Zusatz 300/wdth 100, Reiter 500/wdth 100; Familjen Grotesk für Text, Preiszeilen 500 1.0625rem, Rubriken/Labels 500 0.8125rem Versal +0.06em",
     "farben": "#f4e9e4 Puder (Grund), #1e1412 Espresso (Text), #9b1d2e Lackrot nur für „Termin buchen“, gewählte Chips und aktiven Reiter (Weiß darauf 8:1), #e9dbd4 Karte und gewählte Längenspalte, #6e5a55 Meta (5,4:1 auf Puder, 4,8:1 auf #e9dbd4), #d9c8c0 Linien",
     "kurve": "cubic-bezier(0.625, 0.05, 0, 1) für alles (token-studio-signatur)",
     "dauer_ms": "250 Hover und Farbe, 400 Reiter-Unterstrich, Popover und Preiswechsel (Deckkraft 0 → 1, translate −4 px → 0)",
     "tabelle": "<table> mit <caption>, th scope=col/row; Spalten Leistung | Dauer | kurz | schulterlang | lang, Preise rechtsbündig tabular-nums; gewählte Länge als Spalte #e9dbd4; Preise je Stufe in data-p=\"junior|stylist|master\" (Junior ×0,8, Master ×1,2 der Stylist-Preise, gerundet), „–“ mit Text „nicht bei Junior“",
     "ab_preis": "Knopf „ab“ (min. 30 × 24 px) öffnet das vorhandene Popover am Anker --kz: „ab-Preis · wovon er abhängt“ mit 2–3 Gründen und „Endpreis nach Beratung“; Fußzeile mit Lackrot-Rand wiederholt den Satz",
     "telefon": "Container unter 560 px: nur die gewählte Längenspalte, Dauer wandert unter den Leistungsnamen; unter 420 px Reiter 1.0625rem ohne Silbentrennung",
     "reiter": "Damen · Herren · Farbe · Pflege (APG-Tabs wie die Grundvariante)"
    }
   }
  ]
 }
}
