{
  "id": "apex-evergreen-brand-rules",
  "title": "Apex Instruments brand rules, Evergreen system",
  "version": "1.4",
  "effective": "2026-09-01",
  "owner": "Marketing Lead",
  "note": "The published rule set the brand guardian checks against. Apex Instruments is fictional and so is this rule set, but the shape is the shape a real one takes: named tokens, one rule per line item, a severity, and a fix that says who decides.",
  "settings": {
    "nearMissDistance": 28,
    "minBodyPx": 15,
    "labelMinPx": 10,
    "labelSelectorHints": ["label", "eyebrow", "mono", "caption", "legal", "footnote", "kicker", "meta"],
    "maxOrangePerView": 1,
    "logoSelectorHints": ["logo", "wordmark", "apex-mark", "brand-mark", "spark"],
    "logoAspect": 1,
    "logoAspectTolerance": 0.02,
    "logoColors": ["#00272C", "#FFFFFF", "#245D63"],
    "logoColorNote": "Navy, white, or steel. Nothing else, ever."
  },
  "colors": [
    { "token": "--v-ink", "name": "Evergreen navy", "hex": "#00272C", "aliases": [], "use": "Headings, dark panels, the wordmark" },
    { "token": "--v-steel", "name": "Steel", "hex": "#245D63", "aliases": [], "use": "Secondary headings, rules, chart strokes" },
    { "token": "--v-orange", "name": "Accent orange", "hex": "#FF6B1C", "aliases": [], "use": "One accent per view. Never body text.", "accent": true },
    { "token": "--v-paper", "name": "Page", "hex": "#F4F7F7", "aliases": [], "use": "Page background" },
    { "token": "--v-soft", "name": "Mist", "hex": "#EDF3F3", "aliases": ["#EDF2F3"], "use": "Panel and table backgrounds" },
    { "token": "--v-ice", "name": "Ice", "hex": "#A8B6B7", "aliases": [], "use": "Disabled text, hairlines on dark" },
    { "token": "--v-muted", "name": "Muted text", "hex": "#476467", "aliases": ["#476367"], "use": "Body text at secondary weight, captions" },
    { "token": "--v-line", "name": "Line", "hex": "#DEE3E4", "aliases": ["#D6DFE0"], "use": "Borders and dividers" },
    { "token": "--v-white", "name": "White", "hex": "#FFFFFF", "aliases": ["#FFF"], "use": "Cards, reversed type on navy" },
    { "token": "--v-success", "name": "Success green", "hex": "#09E85E", "aliases": [], "use": "Status badges only. Never a background for text." }
  ],
  "fonts": {
    "approved": [
      { "family": "Archivo", "role": "Headings", "weights": "700 to 900" },
      { "family": "IBM Plex Sans", "role": "Body copy", "weights": "400 to 600" },
      { "family": "IBM Plex Mono", "role": "Uppercase labels, tracking .12em", "weights": "400 to 500" }
    ],
    "allowedGenerics": ["sans-serif", "serif", "monospace", "system-ui", "ui-monospace", "inherit", "initial", "unset"],
    "substitutions": {
      "helvetica neue": "IBM Plex Sans",
      "helvetica": "IBM Plex Sans",
      "arial": "IBM Plex Sans",
      "roboto": "IBM Plex Sans",
      "segoe ui": "IBM Plex Sans",
      "inter": "IBM Plex Sans",
      "open sans": "IBM Plex Sans",
      "lato": "IBM Plex Sans",
      "source sans pro": "IBM Plex Sans",
      "noto sans": "IBM Plex Sans",
      "-apple-system": "IBM Plex Sans",
      "blinkmacsystemfont": "IBM Plex Sans",
      "georgia": "Archivo",
      "times new roman": "Archivo",
      "times": "Archivo",
      "garamond": "Archivo",
      "montserrat": "Archivo",
      "poppins": "Archivo",
      "oswald": "Archivo",
      "courier new": "IBM Plex Mono",
      "courier": "IBM Plex Mono",
      "menlo": "IBM Plex Mono",
      "monaco": "IBM Plex Mono",
      "consolas": "IBM Plex Mono",
      "sf mono": "IBM Plex Mono"
    },
    "stacks": {
      "Archivo": "Archivo, sans-serif",
      "IBM Plex Sans": "'IBM Plex Sans', sans-serif",
      "IBM Plex Mono": "'IBM Plex Mono', monospace"
    }
  },
  "rules": [
    {
      "id": "BR-01",
      "name": "Colour outside the approved palette",
      "severity": "blocker",
      "autofix": false,
      "checks": "Every colour value in the snippet resolves to an approved token.",
      "why": "A colour nobody approved cannot be reproduced in print, on the site, or in a partner deck. It becomes a second palette by accident.",
      "fix": "Replace it with an approved token. The nearest one is named in the finding, but a person picks the right one because the nearest colour is not always the right role."
    },
    {
      "id": "BR-02",
      "name": "Near miss on an approved colour",
      "severity": "blocker",
      "autofix": true,
      "checks": "A colour within 28 units of an approved token but not equal to it.",
      "why": "A near miss is worse than a wrong colour because nobody notices it. Two panels sit side by side and one of them is quietly off.",
      "fix": "Snap it to the token it is imitating. This is mechanical, so the guardian will do it."
    },
    {
      "id": "BR-03",
      "name": "Font family outside the approved set",
      "severity": "blocker",
      "autofix": true,
      "checks": "Every font-family declaration resolves to Archivo, IBM Plex Sans, IBM Plex Mono, or an allowed generic fallback.",
      "why": "A stray stack means one browser renders the page in the brand and another does not. The substitution table decides which approved family stands in.",
      "fix": "Substitute the approved family the table names. This is mechanical, so the guardian will do it."
    },
    {
      "id": "BR-04",
      "name": "More than one orange accent in a view",
      "severity": "blocker",
      "autofix": false,
      "checks": "Accent orange appears at most once per view.",
      "why": "Orange is the only thing on the page that says look here. Used twice it says nothing.",
      "fix": "Keep one. A person decides which one, because that is a decision about what the page is for."
    },
    {
      "id": "BR-05",
      "name": "Body text below the minimum size",
      "severity": "blocker",
      "autofix": false,
      "checks": "No font-size below 15px outside the label roles. Labels may go to 10px.",
      "why": "Fifteen pixels is the floor the brand set for body copy after a legibility pass. Below it the page fails on a phone and in print.",
      "fix": "Raise the size or move the text to a label role. A person decides, because raising a size moves the layout."
    },
    {
      "id": "BR-06",
      "name": "Heading levels out of order",
      "severity": "blocker",
      "autofix": false,
      "checks": "Headings run in order and never skip a level.",
      "why": "A skipped level is how a screen reader loses the outline of the page, and how a page fails an accessibility review.",
      "fix": "Either demote the heading or add the level that is missing. A person decides, because the answer depends on what the section means."
    },
    {
      "id": "BR-07",
      "name": "Inline style overriding a token",
      "severity": "warning",
      "autofix": false,
      "checks": "No style attribute sets colour, background, font-family, font-size, or fill.",
      "why": "An inline style is invisible to the design system. The token can change and this element will not.",
      "fix": "Move the declaration into a class that uses the token. A person does this, because it needs a class name."
    },
    {
      "id": "BR-08",
      "name": "Logo recoloured or stretched",
      "severity": "blocker",
      "autofix": false,
      "checks": "The wordmark and the spark mark use navy, white, or steel only, keep a 1:1 aspect on the mark, and are never scaled unevenly.",
      "why": "The logo is the one asset that has to look the same everywhere. A recolour or a stretch is the fastest way to make a company look careless.",
      "fix": "Restore the approved colour and scale the mark evenly. A person does this, because it usually means going back to the asset."
    }
  ]
}
