{
  "$schema": "masticfrog design tokens v1.1",
  "brand": {
    "name": "masticfrog",
    "domain": "masticfrog.de",
    "wordmark": "masticfrog.de",
    "wordmarkRules": "Immer komplett klein und mit Endung. Nie „Masticfrog“, nie in Versalien, nie ohne .de. Silkscreen im Hero, Mono in Kopfzeile und Kacheln."
  },
  "resin": {
    "resin-100": { "hex": "#fffaf0", "use": "Augenweiß im Logo" },
    "resin-200": { "hex": "#f6e7b4", "use": "Bauch, Text auf Ink" },
    "resin-400": { "hex": "#e0c377", "use": "Amber, Akzent" },
    "resin-600": { "hex": "#b8933f", "use": "Schatten" },
    "resin-800": { "hex": "#6b4f1a", "use": "Kontur" },
    "ink": { "hex": "#2b2114", "use": "Logo-Träger, Primärbutton (light)" }
  },
  "light": {
    "surface/page": "#eae2d2",
    "surface/panel": "#f9f6ef",
    "surface/ink": "#2b2114",
    "border/hairline": "#cabda3",
    "border/strong": "#8a7159",
    "text/heading": "#1a1309",
    "text/body": "#40382a",
    "text/muted": "#6b6152",
    "accent": "#8a5c00",
    "button/primary-bg": "#1a1309",
    "button/primary-fg": "#f6e7b4",
    "status/success": "#2f6b1f",
    "status/success-bg": "#dcefd0",
    "status/warning": "#8a5300",
    "status/warning-bg": "#fbe6b4",
    "status/danger": "#a81f0e",
    "status/danger-bg": "#fbdcd6",
    "status/info": "#1c4a72",
    "status/info-bg": "#d4e6f5",
    "link": "#8a5c00",
    "link-hover": "#1a1309",
    "on-accent": "#fffaf0",
    "on-danger": "#fffaf0"
  },
  "dark": {
    "surface/page": "#100e0b",
    "surface/panel": "#1e1b16",
    "surface/ink": "#2b2114",
    "border/hairline": "#463f33",
    "border/strong": "#786e5a",
    "text/heading": "#fdf8ee",
    "text/body": "#d8cdb4",
    "text/muted": "#a3947a",
    "accent": "#f0cf7e",
    "button/primary-bg": "#f0cf7e",
    "button/primary-fg": "#1a1309",
    "status/success": "#96e06a",
    "status/success-bg": "#1a2612",
    "status/warning": "#ffc44d",
    "status/warning-bg": "#2b2110",
    "status/danger": "#ff8e79",
    "status/danger-bg": "#2e1613",
    "status/info": "#7cc4ff",
    "status/info-bg": "#121e2b",
    "link": "#f0cf7e",
    "link-hover": "#fdf8ee",
    "on-accent": "#1a1309",
    "on-danger": "#2b1109"
  },
  "typography": {
    "families": {
      "pixel": "'Pixelify Sans', monospace",
      "mono": "'Space Mono', monospace",
      "sans": "'Instrument Sans', system-ui, sans-serif"
    },
    "scale": {
      "display/pixel": {
        "family": "pixel",
        "size": 44,
        "weight": 400,
        "tracking": "0.02em",
        "use": "nur Wortmarke / Hero-Titel, nie < 20px"
      },
      "display/xl": { "family": "mono", "size": 48, "weight": 700, "tracking": "-0.03em" },
      "heading/lg": { "family": "mono", "size": 32, "weight": 700, "tracking": "-0.02em" },
      "heading/sm": { "family": "mono", "size": 20, "weight": 700, "tracking": "-0.01em" },
      "body/lg": { "family": "sans", "size": 16, "weight": 400, "lineHeight": 1.6 },
      "body/sm": { "family": "sans", "size": 13, "weight": 400, "lineHeight": 1.55 },
      "label/mono": {
        "family": "mono",
        "size": 10,
        "weight": 400,
        "tracking": "0.16em",
        "transform": "uppercase"
      }
    },
    "weights": { "pixel": [400, 600], "mono": [400, 700], "sans": [400, 500, 600] },
    "note": "Space Mono kennt nur 400 und 700. Labels laufen durchgehend mit 0.16em Tracking.",
    "fallback": "Lädt Pixelify Sans nicht, tritt Space Mono in Versalien an ihre Stelle. Keine System-Serif, kein Silkscreen.",
    "hosting": {
      "mode": "auf eigener Infrastruktur",
      "format": "woff2, @font-face, font-display: swap, nur benutzte Schnitte",
      "sources": "fonts.masticfrog.de oder das eigene Verzeichnis des Projekts. Beides ist unsere Infrastruktur, beides ist erlaubt.",
      "cdn": "kein fremder Font-Host im Produktivbetrieb: kein Google Fonts, kein Bunny, kein jsDelivr. Mockups dürfen laden, was greifbar ist.",
      "rationale": "Die Regel richtet sich gegen die Abhängigkeit von einem fremden Server, nicht gegen einen zweiten Ursprung an sich. Ein fremder Font-Host sieht jeden Besucher, kann jederzeit verschwinden und liegt außerhalb unserer Kontrolle. fonts.masticfrog.de ist dieselbe Maschine wie alles andere.",
      "license": "alle drei Familien SIL Open Font License, der Lizenztext begleitet die Dateien",
      "requirement": "Jede künftige Schrift muss frei herunterladbar und selbst hostbar sein."
    }
  },
  "spacing": { "space-1": 8, "space-2": 20, "space-3": 40, "space-4": 76 },
  "geometry": {
    "radius": 0,
    "shadow": "none",
    "borderWidth": 1,
    "container": 1120,
    "gutter": 40,
    "columns": 12,
    "columnGap": 20
  },
  "breakpoints": { "cols-12": ">= 900px", "cols-6": "600–899px", "cols-1": "< 600px" },
  "icons": {
    "library": "frei wählbar, react-icons in Ordnung; eine Bibliothek pro Bildschirm",
    "style": "outline",
    "strokeWidth": 1.5,
    "color": "currentColor",
    "sizes": [14, 16, 20],
    "max": 20,
    "forbidden": ["gefüllte Icons", "mehrfarbige Icons", "mehrere Bibliotheken auf einem Bildschirm"],
    "note": "Der Guide zeigt Lucide als Beispiel, nicht als Vorschrift."
  },
  "interaction": {
    "hitTarget": 44,
    "hitGap": 8,
    "focusRing": { "width": 2, "color": "accent", "offset": 3 },
    "hover": "120ms ease-out, Flächenfarbe eine Stufe, keine Größenänderung",
    "active": "60ms ease-out, Fläche zwei Stufen, 1px nach unten",
    "disabled": "opacity 0.4, kein Hover, kein Pointer",
    "loading": "Label bleibt, Icon rotiert 800ms",
    "motionMax": 200,
    "reducedMotion": "respektiert, dann ohne Übergang",
    "animatable": ["opacity", "transform", "background-color", "border-color", "color"]
  },
  "contrast": { "bodyText": 4.5, "largeTextAndIcons": 3, "controlBorders": 3 },
  "logo": {
    "grid": "24×24 px",
    "minSize": 24,
    "scaleStep": 24,
    "background": "immer #2b2114 (Ink), in beiden Modi",
    "rendering": "image-rendering: pixelated",
    "forbidden": ["smooth resampling", "rotation", "stretch", "recolour outside resin"]
  },
  "data": {
    "numbers": {
      "family": "mono",
      "variant": "tabular-nums",
      "locale": "de-DE",
      "thousands": ".",
      "decimal": ",",
      "unitSeparator": "geschütztes Leerzeichen",
      "emptyValue": "– (text/muted)",
      "exception": "Technische Ausgaben, die ein Werkzeug wörtlich durchreicht (Dateigrößen, Logzeilen, Versionen), bleiben unverändert."
    },
    "table": {
      "rowPadding": "13px 18px",
      "headerLabel": "label/mono",
      "divider": "1px border/hairline",
      "zebra": false,
      "numericAlign": "right",
      "textAlign": "left",
      "totalRow": "1px border/strong darüber, weight 600"
    },
    "chart": {
      "series": {
        "light": {
          "series/1": "#8a5c00",
          "series/2": "#14595b",
          "series/3": "#6b2f52",
          "series/4": "#3d3a34"
        },
        "dark": {
          "series/1": "#f0cf7e",
          "series/2": "#6fd0cf",
          "series/3": "#e996bf",
          "series/4": "#b3aa98"
        },
        "note": "Vier unterschiedliche Farbtöne mit gestaffelter Helligkeit, nicht vier Abstufungen einer Farbe. Muss in Graustufen und bei Farbsehschwäche unterscheidbar bleiben. Pro Modus getrennt, jede Reihe ≥ 3:1 gegen surface/panel."
      },
      "maxSeries": 4,
      "always": [
        "Nullpunkt sichtbar",
        "Werte direkt am Element",
        "Unterscheidbar auch ohne Farbe",
        "Einheit einmal genannt"
      ],
      "never": [
        "Verläufe / Schatten / 3D / Radien",
        "Torte oder Ring mit > 2 Segmenten",
        "zweite Y-Achse",
        "Statusfarben als Reihenfarben"
      ],
      "singleSeriesException": "Zeigt ein Diagramm genau einen Zustand (Auslastung, freier Speicher), ist die passende Statusfarbe die richtige Füllung."
    }
  },
  "navigation": {
    "label": "label/mono, uppercase, tracking 0.16em",
    "activeMarker": "2px solid accent (border-bottom)",
    "hover": "nur Textfarbe → text/heading",
    "itemMinHeight": 44,
    "mobileItemHeight": 56,
    "mobileBreakpoint": "< 600px",
    "maxItemsPerLevel": 5,
    "maxDepth": 2,
    "sidebarWidth": "260–300px",
    "required": [
      "aria-current=\"page\"",
      "Sprunglink als erstes fokussierbares Element",
      "Escape schließt, Fokus kehrt zum Auslöser zurück",
      "<nav> + <ul>/<li> + <a href>"
    ],
    "footer": {
      "background": "surface/ink (#2b2114) in beiden Modi",
      "linkColor": "#e0c377",
      "linkHover": "#fffaf0",
      "columns": "max. 3 + Markenblock",
      "smallPrint": "label/mono, uppercase, #9a8c6c (war #6b6250, nur 2.62 : 1 gegen Ink)",
      "legalRow": "eigene Zeile unten, border-top 1px #453721, Trefferfläche 44px",
      "required": ["Impressum", "Datenschutz", "Barrierefreiheit"]
    },
    "buttonVsLink": "Rolle entscheidet: Aktion = Button (mono 13px, 13/22 Padding). Seitenwechsel = Navigationsregeln (mono 10px, uppercase, 0.16em), auch in einer Zeile mit Buttons.",
    "colophon": "Einzeiliges Kolophon in Werkzeugen: auf surface/page, Mono-Versalien in text/muted. Die Ink-Fußzeile mit Amber-Links gilt nur für die Website mit Linkspalten."
  },
  "controls": {
    "field": {
      "height": 44,
      "padding": "0 14px",
      "background": "surface/page",
      "border": "1px border/strong",
      "focus": "border accent + 2px outline accent, offset 2",
      "error": "border status/danger + Hinweistext in status/danger",
      "disabled": "opacity 0.4",
      "labelAlwaysVisible": true
    },
    "checkbox": {
      "size": 20,
      "radius": 0,
      "checked": "Fläche accent, Häkchen in on-accent (Strichstärke 3)",
      "indeterminate": "minus-Icon",
      "disabled": "opacity 0.4"
    },
    "radio": {
      "size": 20,
      "radius": "50%, der einzige Kreis im System",
      "dot": 10,
      "note": "Kreis nur damit Radio und Checkbox unterscheidbar bleiben"
    },
    "switch": {
      "track": "48×26, padding 3",
      "knob": "18×18 quadratisch",
      "on": "Track accent, Knob on-accent",
      "off": "Track transparent mit border/strong, Knob in text/heading; Knob und Track nie gleichfarbig",
      "behaviour": "schaltet sofort, kein Bestätigen-Button",
      "aria": "role=switch + aria-checked"
    },
    "segmented": {
      "itemHeight": 44,
      "active": "Fläche button/primary-bg, Text button/primary-fg",
      "container": "1px border/strong"
    },
    "slider": {
      "track": 4,
      "fill": "accent",
      "knob": "14×22 auf button/primary-bg mit accent-Rahmen",
      "hitArea": 44
    },
    "progress": { "height": 8, "track": "border/hairline", "fill": "accent" },
    "skeleton": { "blocks": "flach in border/hairline, kein Schimmern, kein Puls" },
    "dialog": {
      "surface": "surface/page",
      "border": "1px border/strong",
      "shadow": "none",
      "radius": 0,
      "close": "44×44 Button mit aria-label",
      "primaryAction": "rechts, destruktiv nur wenn Primäraktion"
    },
    "tooltip": { "surface": "button/primary-bg", "text": "button/primary-fg", "arrow": "none" },
    "pagination": { "item": "min 44×44", "active": "Fläche button/primary-bg + aria-current=page" }
  }
}
