[
  {
    "id": "W1",
    "medium": "web",
    "name": "Mobile-first, capped measure",
    "threshold": "no horizontal overflow at 320; shell max-width 1200–1440; prose ≤75ch; min-width media queries",
    "unit": "px / ch",
    "source": "Marcotte; Frost",
    "check": "measured",
    "howMeasured": "Document scroll width at 320 px; the widest centred container's max-width; prose max-width; media query direction."
  },
  {
    "id": "W2",
    "medium": "web",
    "name": "Content-driven breakpoints",
    "threshold": "breakpoints near 640/768/1024/1280; zero horizontal scroll at 320, 390, 768, 1024, 1440",
    "unit": "px",
    "source": "Frost; Tailwind",
    "check": "measured",
    "howMeasured": "Media query widths read from the stylesheet; document scroll width at five viewports."
  },
  {
    "id": "W3",
    "medium": "web",
    "name": "Fluid type via clamp()",
    "threshold": "h1 and body font-size use clamp(); no bare vw on type",
    "unit": "",
    "source": "Utopia, Mudford & Gilyead",
    "check": "measured",
    "howMeasured": "Stylesheet font-size declarations on h1 and body selectors inspected for clamp() and bare vw."
  },
  {
    "id": "W4",
    "medium": "web",
    "name": "Body size and tap targets",
    "threshold": "body ≥16 px; buttons, form controls, CTAs and nav links ≥44×44 px; any other link ≥24×24 px",
    "unit": "px",
    "source": "Apple HIG (44); WCAG 2.5.8 (24)",
    "check": "measured",
    "howMeasured": "Computed body font-size; bounding boxes of links, buttons and inputs at 390 px, tiered by role."
  },
  {
    "id": "W5",
    "medium": "web",
    "name": "One primary action per view",
    "threshold": "≤1 primary control per viewport-height slice",
    "unit": "controls",
    "source": "Krug; Hick's Law",
    "check": "proxy",
    "howMeasured": "Primary controls derived by accent fill (background within a colour distance of the brand accent); the file's data-role only cross-checked."
  },
  {
    "id": "W6",
    "medium": "web",
    "name": "The fold answers what, who, next",
    "threshold": "h1 ≤12 words, a subline and the primary control inside the first viewport at 1366×768 and 390×844; nav ≤72 px on mobile",
    "unit": "",
    "source": "NN/g; Krug",
    "check": "proxy",
    "howMeasured": "Positions of h1, first paragraph and first primary control against the viewport; the comprehension claim is ASSERTED."
  },
  {
    "id": "W7",
    "medium": "web",
    "name": "Scan patterns; left-aligned body",
    "threshold": "body paragraphs never justified; prose not centred",
    "unit": "",
    "source": "NN/g; Butterick",
    "check": "measured",
    "howMeasured": "Computed text-align on paragraphs longer than 40 words."
  },
  {
    "id": "W8",
    "medium": "web",
    "name": "Measure 45–75 characters",
    "threshold": "45–75 characters per rendered line on prose",
    "unit": "characters",
    "source": "Bringhurst; Butterick",
    "check": "measured",
    "howMeasured": "Per rendered line via Range rectangles, as S10, on paragraphs of 40+ words at 1440 px."
  },
  {
    "id": "W9",
    "medium": "web",
    "name": "Line height and paragraph spacing",
    "threshold": "body ≥1.5, display 1.0–1.25, paragraph spacing ≥0.75em",
    "unit": "ratio / em",
    "source": "WCAG 1.4.12; Bringhurst",
    "check": "measured",
    "howMeasured": "Computed line-height ÷ font-size and margin-bottom ÷ font-size on paragraphs and headings."
  },
  {
    "id": "W10",
    "medium": "web",
    "name": "8-point spacing, one type scale",
    "threshold": "spacing in {4,8,12,16,24,32,48,64,96,128}; one modular scale",
    "unit": "px",
    "source": "Material; Bryn Jackson",
    "check": "measured",
    "howMeasured": "Computed margin, padding and gap values; distinct font sizes checked for a consistent ratio."
  },
  {
    "id": "W11",
    "medium": "web",
    "name": "WCAG 2.2 AA contrast",
    "threshold": "text ≥4.5:1, large text ≥3:1, UI ≥3:1",
    "unit": "ratio",
    "source": "WCAG 2.2 1.4.3 / 1.4.11",
    "check": "measured",
    "howMeasured": "WCAG formula on computed text and control colours versus effective background."
  },
  {
    "id": "W12",
    "medium": "web",
    "name": "Semantic OKLCH tokens",
    "threshold": "--color-bg/fg/accent/muted/border defined on :root in oklch(); component colour declarations resolve through var(--color-*)",
    "unit": "",
    "source": "W3C Design Tokens CG; Ottosson",
    "check": "proxy",
    "howMeasured": "Stylesheet: root custom properties present and in oklch(); share of colour declarations outside :root that use var()."
  },
  {
    "id": "W13",
    "medium": "web",
    "name": "Five interaction states",
    "threshold": "hover, focus-visible, active, disabled rules per interactive selector; focus ring ≥2 px, ≥3:1, not clipped",
    "unit": "",
    "source": "WCAG 2.4.11 / 2.4.13; Radix",
    "check": "measured",
    "howMeasured": "Stylesheet rules per interactive selector; after element.focus(), computed outline/box-shadow width, its contrast against adjacent colours, and whether its rect is clipped. Visibility under real conditions is ASSERTED."
  },
  {
    "id": "W14",
    "medium": "web",
    "name": "Empty, loading and error states",
    "threshold": "form error affordance present (aria-invalid styling, aria-describedby)",
    "unit": "",
    "source": "NN/g; Refactoring UI",
    "check": "proxy",
    "howMeasured": "Form error affordances measured; empty and loading states are ASSERTED."
  },
  {
    "id": "W15",
    "medium": "web",
    "name": "Motion discipline",
    "threshold": "transitions 150–300 ms; prefers-reduced-motion reset present; only transform and opacity animated; no autoplay without controls",
    "unit": "ms",
    "source": "Material motion; WCAG 2.2.2 / 2.3.3",
    "check": "measured",
    "howMeasured": "Transition durations, the reduced-motion media rule, animated properties in keyframes, video autoplay attributes."
  },
  {
    "id": "W16",
    "medium": "web",
    "name": "Reserve space",
    "threshold": "every image, video and iframe sized or given an aspect ratio; CLS reported as a lab number",
    "unit": "",
    "source": "web.dev Core Web Vitals",
    "check": "proxy",
    "howMeasured": "Size attributes and aspect-ratio measured; cumulative layout shift from a lab observer reported, not graded."
  },
  {
    "id": "W17",
    "medium": "web",
    "name": "Performance budget",
    "threshold": "≤2 font families; preload present; transfer size reported; LCP lab number reported; INP not measured",
    "unit": "KB / ms",
    "source": "web.dev; Addy Osmani",
    "check": "proxy",
    "howMeasured": "Font families and preload measured; transfer size and LCP reported from a lab run and labelled as such; INP is stated as not measured."
  },
  {
    "id": "W18",
    "medium": "web",
    "name": "Landmarks, skip link, one h1",
    "threshold": "header, nav, main, footer present; first focusable is the skip link; exactly one h1; no skipped heading levels; Tab order equals DOM order",
    "unit": "",
    "source": "WCAG 1.3.1 / 2.4.1",
    "check": "measured",
    "howMeasured": "Landmark elements, heading sequence, first focusable element, and the DOM-versus-visual order of focusable elements."
  },
  {
    "id": "W19",
    "medium": "web",
    "name": "Forms",
    "threshold": "every input labelled; type and autocomplete set; single column; error text linked to its field",
    "unit": "",
    "source": "Baymard; WCAG 3.3",
    "check": "measured",
    "howMeasured": "Label association, type and autocomplete attributes, input width versus form width, aria-describedby on invalid fields."
  },
  {
    "id": "W20",
    "medium": "web",
    "name": "Meta layer",
    "threshold": "title ≤60, description ≤155, og:image declared 1200×630, theme-color, favicon, JSON-LD parses",
    "unit": "characters",
    "source": "Open Graph; schema.org",
    "check": "measured",
    "howMeasured": "Document head read after load; JSON-LD parsed."
  },
  {
    "id": "W21",
    "medium": "web",
    "name": "Show, do not only tell",
    "threshold": "at least one non-decorative visual above the fold, and one visual per 2 content sections",
    "unit": "visuals",
    "source": "Ours, 2026-09-03",
    "check": "measured",
    "howMeasured": "Non-decorative images, inline SVG figures, video and embedded demos are counted per section from the rendered page; the logo and decorative marks are excluded. A page of pure text fails."
  },
  {
    "id": "W22",
    "medium": "web",
    "name": "Evidence a stranger can check",
    "threshold": "a proof section carrying at least one of: a named testimonial, a customer logo set, a screenshot of the thing working, or a specific number",
    "unit": "",
    "source": "Ours, 2026-09-03",
    "check": "proxy",
    "howMeasured": "Looks for a section marked proof, or a testimonial/figure/logo group, or a digit-bearing claim outside the nav and footer. Presence is measured; whether the evidence is TRUE or persuasive is not, and never claimed."
  }
]
