{
  "$meta": {
    "brand": "NimboCDN",
    "version": "1.0.0",
    "date": "2026-08",
    "direction": "Option 4 · The Cut",
    "description": "Official design tokens. The symbol is an image that loses 32% of its height and gives that mass back as the edge it is delivered from; the 32% is the measurement the product publishes, not a proportion picked by eye.",
    "typeface_license": "Bricolage Grotesque and Figtree: SIL Open Font License 1.1 (free for commercial use). Copies in fonts/OFL-*.txt.",
    "generated_by": "brand-kit/tools/build_tokens.py, translated by brand-kit/tools/tokens_en.py"
  },
  "color": {
    "core": {
      "plum-700": {
        "name": "Plum 700",
        "css": "--nimbo-plum-700",
        "hex": "#7A0F5C",
        "rgb": "122 15 92",
        "hue": 317,
        "contrast_on_white": 10.24,
        "contrast_on_wp_grey": 8.99,
        "usage": "Icon field and interactive primary: buttons, focus"
      },
      "lime": {
        "name": "Lime",
        "css": "--nimbo-lime",
        "hex": "#C8F53C",
        "rgb": "200 245 60",
        "hue": 75,
        "contrast_on_white": 1.27,
        "contrast_on_wp_grey": 1.11,
        "usage": "The edge. The only accent — ONLY on the field, never text on a light background"
      },
      "pink-100": {
        "name": "Pink 100",
        "css": "--nimbo-pink-100",
        "hex": "#FFD9F0",
        "rgb": "255 217 240",
        "hue": 324,
        "contrast_on_white": 1.28,
        "contrast_on_wp_grey": 1.12,
        "usage": "The knocked-out block inside the field"
      },
      "ink": {
        "name": "Ink",
        "css": "--nimbo-ink",
        "hex": "#1C1019",
        "rgb": "28 16 25",
        "hue": 315,
        "contrast_on_white": 18.46,
        "contrast_on_wp_grey": 16.21,
        "usage": "Body text"
      },
      "bg": {
        "name": "Background",
        "css": "--nimbo-bg",
        "hex": "#FBF6F9",
        "rgb": "251 246 249",
        "hue": "achromatic",
        "contrast_on_white": 1.07,
        "contrast_on_wp_grey": 1.07,
        "usage": "Page background"
      }
    },
    "semantic": {
      "_rule": "Feedback has its OWN colours, never the brand ones. NimboCDN's plum is not an error and lime is not a success: if a warning looks like the brand accent, people stop reading warnings.",
      "ok": {
        "hex": "#1C7C3E",
        "contrast_on_bg": 4.91
      },
      "warning": {
        "hex": "#8A5A00",
        "contrast_on_bg": 5.55
      },
      "error": {
        "hex": "#B3261E",
        "contrast_on_bg": 6.12
      }
    },
    "themes": {
      "light": {
        "bg": "#FBF6F9",
        "surface": "#FFFFFF",
        "surface-2": "#F3E8F0",
        "text": "#1C1019",
        "text-muted": "#6B5766",
        "accent": "#7A0F5C",
        "on-accent": "#FFFFFF",
        "accent-hover": "#8C1A6A",
        "accent-active": "#5C1246",
        "focus": "#7A0F5C",
        "link": "#7A0F5C",
        "link-hover": "#8C1A6A",
        "highlight": "#C8F53C",
        "border": "#E7D6E2"
      },
      "dark": {
        "bg": "#16090F",
        "surface": "#21121B",
        "surface-2": "#332030",
        "text": "#F7EBF3",
        "text-muted": "#B9A3B2",
        "accent": "#FFD9F0",
        "on-accent": "#2B0D20",
        "accent-hover": "#FFE9F6",
        "accent-active": "#F0B7DD",
        "focus": "#C8F53C",
        "link": "#FFD9F0",
        "link-hover": "#FFE9F6",
        "highlight": "#C8F53C",
        "border": "#3A2233"
      },
      "_note": "Lime is NEVER text on a light background: 1.27:1 against white. It lives on the plum field, where it reaches 8.09:1, and as an underline or a bar. In the dark theme it may be the focus ring, because there the background is dark."
    },
    "wcag_accessibility": {
      "measured": true,
      "_source": "brand-kit/tools/contrast.py",
      "aa_pairs": [
        [
          "ink/bg",
          17.28
        ],
        [
          "field/white",
          10.24
        ],
        [
          "field/wp-grey",
          8.99
        ],
        [
          "white/field",
          10.24
        ],
        [
          "pink/field",
          8.02
        ],
        [
          "lime/field",
          8.09
        ],
        [
          "ok/bg",
          4.91
        ],
        [
          "warning/bg",
          5.55
        ],
        [
          "error/bg",
          6.12
        ]
      ],
      "forbidden": [
        [
          "lime as text on a light background",
          1.27,
          "never: only a bar, an underline or a graphic on the dark field"
        ],
        [
          "pink as text on a light background",
          1.28,
          "never: pink is the knocked-out block inside the field, not an ink"
        ]
      ],
      "_rule_graphics": "WCAG 2.2 SC 1.4.11 asks 3:1 of a GRAPHIC, not the 4.5:1 of SC 1.4.3 that governs text. The icon field meets the graphic threshold against both possible marketplace backgrounds; that does NOT license the same colour for text."
    },
    "usage_ratios": {
      "plum_fields_and_action": 55,
      "neutrals_and_background": 32,
      "lime_accent_only": 8,
      "semantic_feedback_only": 5
    }
  },
  "typography": {
    "display": {
      "family": "Bricolage Grotesque",
      "fallback": "'Helvetica Neue', Arial, sans-serif",
      "weights": [
        500,
        600,
        700,
        800
      ],
      "usage": "Wordmark, headings, featured figures",
      "note": "The woff2 Google Fonts serves is already instanced at opsz 96 and wdth 100: the only live axis is wght, 200–800, defaulting to 800. Every use MUST declare font-weight — otherwise it falls back to 800."
    },
    "text": {
      "family": "Figtree",
      "fallback": "-apple-system, 'Segoe UI', system-ui, sans-serif",
      "weights": [
        400,
        500,
        600,
        700
      ],
      "usage": "UI, body copy, buttons, labels",
      "note": "wght axis 300–900, defaulting to 300. Half the brand lives inside the WordPress admin, which sets type in the system font: this family was chosen to degrade without drama."
    },
    "logo": {
      "construction": "Wordmark as vector outlines, shaped with HarfBuzz's real kerning: Bricolage Grotesque wght 700 / opsz 96 / wdth 100, tracking −30/1000 em. It is not typed: it is generated by brand-kit/tools/generate_logos.py from the outlines cached in tools/wordmark_glyphs.py.",
      "note": "Do not set the name in live type: use the generated lockups.",
      "nimbo_cdn": "\"CDN\" may sit in a different tone from \"Nimbo\": it is the category, not the name, and it tells the reader where the brand ends without introducing a space. In one ink they match — a tone does not survive a single colour."
    },
    "logo_minimums": {
      "symbol": "16 px (favicon, and at that size WITHOUT the glyph)",
      "horizontal_lockup": "96 px wide",
      "favicon_note": "Measured: at 16 px the image glyph drops shape retention to 0.807; without the glyph it rises to 0.882. That is why the favicon uses nimbocdn-symbol-small.svg."
    },
    "scale": {
      "display-xl": {
        "size": "56px/60px",
        "family": "Bricolage Grotesque 700"
      },
      "display-lg": {
        "size": "40px/44px",
        "family": "Bricolage Grotesque 700"
      },
      "heading": {
        "size": "28px/34px",
        "family": "Bricolage Grotesque 600"
      },
      "subheading": {
        "size": "20px/28px",
        "family": "Figtree 600"
      },
      "body": {
        "size": "16px/26px",
        "family": "Figtree 400"
      },
      "caption": {
        "size": "13px/18px",
        "family": "Figtree 500"
      },
      "overline": {
        "size": "11.5px/16px",
        "family": "Figtree 700",
        "tracking": "+0.2em",
        "transform": "uppercase"
      }
    },
    "_hard_rule": "Interactive text never below 12 real px. Reading body copy never below 15–16 px."
  },
  "radius": {
    "sm": "6px",
    "md": "10px",
    "lg": "16px",
    "xl": "24px",
    "pill": "999px"
  },
  "elevation": {
    "_rule": "Shadows tinted with the plum ink in the light theme, never pure black; black only in dark. e0 = flat.",
    "e1": {
      "usage": "fields at rest, chips",
      "light": "0 1px 2px rgba(28,16,25,.06), 0 2px 6px rgba(28,16,25,.05)"
    },
    "e2": {
      "usage": "cards",
      "light": "0 1px 2px rgba(28,16,25,.07), 0 8px 20px rgba(28,16,25,.08)"
    },
    "e3": {
      "usage": "primary CTA, focused field",
      "light": "0 1px 2px rgba(28,16,25,.12), 0 12px 26px rgba(28,16,25,.18)"
    },
    "e4": {
      "usage": "modals, toasts",
      "light": "0 2px 6px rgba(28,16,25,.16), 0 20px 46px rgba(28,16,25,.26)"
    }
  },
  "spacing": {
    "base": 8,
    "scale": [
      4,
      8,
      12,
      16,
      24,
      32,
      48,
      64,
      96
    ]
  },
  "icons": {
    "style": "Monoline, 2px stroke, square terminals (an echo of the symbol's cuts)",
    "grid": "24px"
  },
  "motion": {
    "easing": "cubic-bezier(.22,1,.36,1)",
    "duration": {
      "fast": "180ms",
      "medium": "340ms",
      "slow": "2400ms"
    },
    "signature": {
      "name": "The Cut",
      "spec": "The block loses 32% of its height and that mass reappears as the edge. A 2,400 ms cycle: 0–12% at rest, 12–42% the cut, 42–62% the bar detaches and widens, 62–100% at rest in the final state.",
      "rule": "The final state IS the static logo. Every implementation has to end there, and to start there when prefers-reduced-motion is set."
    },
    "accessibility": {
      "prefers-reduced-motion": "No animation: the final state is shown.",
      "wcag_2_2_2": "A GIF looping forever cannot be paused and therefore fails SC 2.2.2. The icon-256x256-loop3.gif variant runs three times and stops: that is the one uploaded to wordpress.org."
    }
  },
  "symbol": {
    "grid": 24,
    "block": {
      "x": [
        5.0,
        19.0
      ],
      "y": [
        5.5,
        14.34
      ],
      "full_height": 13,
      "final_height": 8.84,
      "radius": 1.6
    },
    "edge": {
      "x": [
        3.2,
        20.8
      ],
      "y": [
        17.0,
        18.5
      ],
      "radius": 0.75
    },
    "proportion": 0.68,
    "_why": "8.84 / 13 = 0.68. The missing 32% is the measurement the product publishes: AVIF needs 32% fewer bytes than JPEG, across 14 images from two real stores at equal perceived quality. If that measurement changes, the symbol changes with it.",
    "clear_space": "1.5 u × 2 = 3 u out of 24, that is one eighth of the symbol's height. It is taken from the height of the lime edge so it scales with the mark instead of being an arbitrary number."
  }
}
