{
  "name": "Rekta Design",
  "version": "0.2.0",
  "units": {
    "length": "logical px (CSS px, Android dp, Apple pt)",
    "duration": "ms",
    "angle": "deg",
    "easing": "cubic-bezier [x1, y1, x2, y2]",
    "fluid": "{min, max, viewport}: interpolate between min and max at viewport × hosting box width"
  },
  "themes": {
    "light": {
      "bg": "#ffffff",
      "surface": "#eeeff2",
      "surface-2": "#e4e5e9",
      "text-primary": "#010205",
      "text-contrast-low": "#d8d8db",
      "text-contrast-medium": "#6b6d70",
      "text-contrast-high": "#535457",
      "accent": "#010205",
      "on-accent": "#ffffff",
      "status-info-full": "#2762ec",
      "status-info-soft": "#d3e1ff",
      "status-info-tile": "#7da1f4",
      "status-success-full": "#007b5d",
      "status-success-soft": "#e1fff2",
      "status-success-tile": "#61caa6",
      "status-warning-full": "#a37e00",
      "status-warning-soft": "#fff4d2",
      "status-warning-tile": "#f8d866",
      "status-error-full": "#aa0013",
      "status-error-soft": "#ffe2e4",
      "status-error-tile": "#c86065",
      "focus": "#1a44ea",
      "hover": "#9495982e",
      "disabled": "#949598",
      "shading": "#010205ab",
      "glass": "#ffffffd1"
    },
    "dark": {
      "bg": "#0e0e12",
      "surface": "#212225",
      "surface-2": "#2a2b2f",
      "text-primary": "#fbfcff",
      "text-contrast-low": "#404044",
      "text-contrast-medium": "#88898c",
      "text-contrast-high": "#afb0b3",
      "accent": "#fbfcff",
      "on-accent": "#0e0e12",
      "status-info-full": "#178bff",
      "status-info-soft": "#04294e",
      "status-info-tile": "#244592",
      "status-success-full": "#00ce9d",
      "status-success-soft": "#003324",
      "status-success-tile": "#337a62",
      "status-warning-full": "#f7cb47",
      "status-warning-soft": "#362b0a",
      "status-warning-tile": "#6e5900",
      "status-error-full": "#fc4040",
      "status-error-soft": "#3a0f0f",
      "status-error-tile": "#76171f",
      "focus": "#178bff",
      "hover": "#9495982e",
      "disabled": "#7e7f82",
      "shading": "#262629ab",
      "glass": "#0e0e12d1"
    }
  },
  "densities": {
    "comfortable": {
      "control-height": 44,
      "row-height": 44,
      "control-padding": 16
    },
    "compact": {
      "control-height": 32,
      "row-height": 32,
      "control-padding": 12
    }
  },
  "typography": {
    "font-sans": [
      "Barlow",
      "Arial Narrow",
      "Arial",
      "sans-serif"
    ],
    "font-mono": [
      "ui-monospace",
      "SFMono-Regular",
      "Menlo",
      "Consolas",
      "monospace"
    ],
    "font-weight-light": 300,
    "font-weight-regular": 400,
    "font-weight-medium": 500,
    "font-weight-semibold": 600,
    "font-weight-bold": 700,
    "font-size-xxs": 12,
    "font-size-xs": 13,
    "font-size-s": 15,
    "font-size-m": 18,
    "font-size-l": {
      "min": 22,
      "max": 28,
      "viewport": 0.015
    },
    "font-size-xl": {
      "min": 26,
      "max": 34,
      "viewport": 0.02
    },
    "font-size-xxl": {
      "min": 30,
      "max": 44,
      "viewport": 0.026
    },
    "font-size-nav-active": {
      "min": 40,
      "max": 72,
      "viewport": 0.042
    },
    "font-size-nav-inactive": {
      "min": 22,
      "max": 32,
      "viewport": 0.019
    },
    "font-size-pivot-active": {
      "min": 28,
      "max": 42,
      "viewport": 0.026
    },
    "font-size-pivot-inactive": {
      "min": 20,
      "max": 26,
      "viewport": 0.016
    },
    "font-size-group": {
      "min": 22,
      "max": 30,
      "viewport": 0.017
    },
    "font-size-title": {
      "min": 30,
      "max": 48,
      "viewport": 0.028
    },
    "line-height-body": 1.5,
    "line-height-compact": 1.35,
    "line-height-tight": 1.15,
    "line-height-title": 1.1,
    "line-height-nav": 1.3
  },
  "spacing": {
    "space-xs": 4,
    "space-s": 8,
    "space-m": 16,
    "space-l": 32,
    "space-xl": 48
  },
  "radius": {
    "radius-s": 4,
    "radius-m": 8,
    "radius-l": 12,
    "radius-tile": 2
  },
  "size": {
    "tile-unit": 150,
    "tile-unit-ultrawide": 170,
    "appbar-height": 56,
    "touch-target": 44,
    "pane-min": 240
  },
  "motion": {
    "duration-press": 100,
    "duration-short": 250,
    "duration-moderate": 400,
    "duration-long": 600,
    "duration-pivot-glide": 500,
    "duration-pivot-size": 220,
    "duration-stagger": 30,
    "duration-pulse": 1400,
    "duration-busy": 1200,
    "duration-float": 150,
    "duration-dots": 2400,
    "ease-base": [
      0.25,
      0.1,
      0.25,
      1
    ],
    "ease-in": [
      0,
      0,
      0.2,
      1
    ],
    "ease-out": [
      0.4,
      0,
      0.5,
      1
    ],
    "ease-pivot-glide": [
      0.65,
      0,
      0.35,
      1
    ],
    "turnstile-angle": 40,
    "turnstile-perspective": 800,
    "slide-distance": 24,
    "tile-tilt": 8,
    "tile-press-scale": 0.97,
    "row-tilt": 2,
    "row-press-scale": 0.99
  },
  "timing": {
    "duration-toast": 5000,
    "duration-wheel-latch": 200,
    "duration-tap-delay": 100,
    "duration-busy-delay": 300,
    "duration-busy-min": 500,
    "duration-tip-delay": 500,
    "duration-long-press": 500,
    "duration-stale": 30000
  },
  "layer": {
    "layer-sticky": 10,
    "layer-appbar": 20,
    "layer-banner": 30,
    "layer-toast": 40,
    "layer-float": 50
  },
  "breakpoint": {
    "bp-mobile": 375,
    "bp-sideways-scroll-min": 760,
    "bp-short-height": 480,
    "bp-desktop": 1440,
    "bp-wide": 1920,
    "bp-ultrawide": 2560
  },
  "descriptions": {
    "bg": "Page ground. Everything sits directly on it; text-primary reads on it.",
    "surface": "Neutral secondary ground: rows, inputs, tiles with no status. text-primary and text-contrast-high read on it.",
    "surface-2": "Hover step of surface.",
    "text-primary": "Primary text on bg, surface, surface-2 and on every status-*-tile fill (checked AA).",
    "text-contrast-low": "Hairlines (1–2px) and disabled borders. Decorative separator, not for text.",
    "text-contrast-medium": "Secondary borders and placeholder text on bg.",
    "text-contrast-high": "Secondary text on bg and surface (AA). Never on a status tile.",
    "accent": "Optional product accent slot: primary button fill, checked controls, a selected item's fill, a link colour if the product wants one. Defaults to ink, so Rekta stays neutral until a product overrides it per theme. Never a tile, never a status; a selected row is the largest fill it takes. Must hold 3:1 on bg and surface and stay clearly apart from every status-*-full hue.",
    "on-accent": "Text and icons on accent. Override together with accent so the pair holds 4.5:1.",
    "status-info-full": "Info (active / in progress). Small marks only: tag square, pulse, sparkline, progress bar. At least 3:1 on bg and surface in both themes.",
    "status-info-soft": "Info (active / in progress). Tint behind a status label in running text (rk-tag--soft); text-primary on it.",
    "status-info-tile": "Info (active / in progress). The only large fill (a tile's whole background); text-primary on it at AA in both themes.",
    "status-success-full": "Success (done). Small marks only: tag square, pulse, sparkline, progress bar. At least 3:1 on bg and surface in both themes. Jade (hue shifted from green toward blue) so it never reads as error under red–green colour blindness.",
    "status-success-soft": "Success (done). Tint behind a status label in running text (rk-tag--soft); text-primary on it.",
    "status-success-tile": "Success (done). The only large fill (a tile's whole background); text-primary on it at AA in both themes. Lighter than status-error-tile in both themes.",
    "status-warning-full": "Warning (waiting / paused). Small marks only: tag square, pulse, sparkline, progress bar. At least 3:1 on bg and surface in both themes. Light value darkened from the source #f3be00 (1.7:1) to pass 3:1.",
    "status-warning-soft": "Warning (waiting / paused). Tint behind a status label in running text (rk-tag--soft); text-primary on it.",
    "status-warning-tile": "Warning (waiting / paused). The only large fill (a tile's whole background); text-primary on it at AA in both themes.",
    "status-error-full": "Error (failed). Small marks only: tag square, pulse, sparkline, progress bar. At least 3:1 on bg and surface in both themes. In light it is the darkest status mark, so it parts from success by lightness too.",
    "status-error-soft": "Error (failed). Tint behind a status label in running text (rk-tag--soft); text-primary on it.",
    "status-error-tile": "Error (failed). The only large fill (a tile's whole background); text-primary on it at AA in both themes. Always the darkest status fill in both themes: failed reads apart from done without hue.",
    "focus": "Focus ring on neutral surfaces (bg, surface), 3:1 or better in both themes. On a status tile use the tile's own text colour as an inset ring instead.",
    "hover": "Translucent neutral overlay laid on top of any fill for pointer hover.",
    "disabled": "Flat grey for disabled text and borders. Never a fill.",
    "shading": "Backdrop behind a sheet or dialog.",
    "glass": "Frosted surfaces (nav bar, app bar); use with a backdrop blur.",
    "font-sans": "The one family. Ship the font files with the app (fonts/), never from a CDN.",
    "font-mono": "Machine text: IDs, code, logs.",
    "font-weight-light": "Navigation titles and a status banner's state word: large and light, never bold.",
    "font-weight-medium": "Tabular figures: stat numbers, counts.",
    "font-weight-semibold": "The one bold title per page (e.g. a record's own title), and small UI words.",
    "font-size-xxs": "Captions, metadata, hex values (rk-meta).",
    "font-size-xs": "Kickers, facts, labels, tags, tile words.",
    "font-size-s": "Body text.",
    "font-size-m": "Sub-headings, emphasised labels.",
    "font-size-l": "Fluid size role.",
    "font-size-xl": "Fluid size role.",
    "font-size-xxl": "Fluid size role.",
    "font-size-nav-active": "Level 1: the place you are at, in the top-level nav.",
    "font-size-nav-inactive": "Fluid size role.",
    "font-size-pivot-active": "Level 2: the active facet within a place.",
    "font-size-pivot-inactive": "Fluid size role.",
    "font-size-group": "Section/group headings inside a view.",
    "font-size-title": "Level 3: a record's own bold title (e.g. a ticket).",
    "line-height-body": "Running text and controls.",
    "line-height-compact": "Tiles, tags, toasts: short lines in tight boxes.",
    "line-height-tight": "Group headings, banner words.",
    "line-height-title": "The one bold title.",
    "line-height-nav": "Pivot titles (their fixed line box).",
    "space-xs": "Tight gaps between inline elements.",
    "space-s": "Grid gap between tiles; padding inside rows.",
    "space-m": "Page padding below 760px; default block gap; button padding.",
    "space-l": "Section padding.",
    "space-xl": "Page padding from 760px up; gap between panorama sections.",
    "radius-s": "Buttons, fields, app-bar controls, toasts.",
    "radius-m": "Bottom corners of a sheet.",
    "radius-l": "Larger dialogs.",
    "radius-tile": "0–2px. Tiles are tiles, not cards: sharp enough to read as Metro, soft enough to read as refined.",
    "tile-unit": "Tile grid cell from 760px up; tiles span 1 or 2 units.",
    "tile-unit-ultrawide": "Tile grid cell from 2560px up.",
    "appbar-height": "Height of the bottom app bar, plus the safe-area inset.",
    "touch-target": "Minimum height and width of any control reached by touch. The app bar's controls use 48px in every density.",
    "pane-min": "The narrowest a pane of a split view may be dragged; below twice this plus the handle the split shows one pane at a time.",
    "control-height": "Buttons, fields, switches, toast actions.",
    "row-height": "Interactive rows (menus, tables, selectable lists).",
    "control-padding": "Inline padding of a button.",
    "duration-press": "A pressed tile sinking back under the pointer or key; it comes back over duration-short. 0s under reduced motion, where the press is a flat, instant sink.",
    "duration-short": "Hover/border/colour state changes, sheets, toasts, and each unit leaving in a place change.",
    "duration-moderate": "Place change (the arriving place of the turnstile), tile build-in, FLIP reflow, pivot title grow.",
    "duration-long": "Live drawing: line charts, growing bars, the toast's undo line.",
    "duration-pivot-glide": "The pivot strip gliding by the newly active title's place in the order. Used with ease-pivot-glide.",
    "duration-pivot-size": "The active pivot title growing and the previous one shrinking (ease-in-out); lighter and quicker than the glide.",
    "duration-stagger": "Delay per tile index when tiles build in, and between the rows of a place leaving in a place change (both capped at 10).",
    "duration-pulse": "One cycle of the live pulse in the app bar. Only for genuinely live data.",
    "duration-busy": "One pass of the indeterminate 2px line that says a region is loading or an action is pending. Under reduced motion the line stands still at full width.",
    "duration-float": "A floating surface (menu, list) appearing next to its control: a fade and a 4px shift away from the control. It leaves at once.",
    "duration-dots": "One flight of the five progress dots across their track: fast in from the leading edge, slow through the middle, fast out. The dots leave one after another.",
    "ease-base": "Default for state changes: nothing snaps, everything glides briefly.",
    "ease-in": "Things arriving: tile build-in, sheets, toasts, live line drawing.",
    "ease-out": "Navigation: place change (turnstile) and facet change (pivot slide).",
    "ease-pivot-glide": "Pronounced ease-in-out of the pivot strip glide.",
    "turnstile-angle": "Place change: a place turns this far around its leading edge while it fades. Forward, the old place swings toward the viewer and the new one swings in from the back; back, the other way round. Degrees.",
    "turnstile-perspective": "Perspective of a pressed tile, and the base perspective of the turnstile (the script adds distance from the axis).",
    "slide-distance": "Facet change: how far the incoming facet travels from its side of the pivot.",
    "tile-tilt": "How far a tile tilts at the edge where it is pressed; pressed in the middle it does not tilt. Degrees.",
    "tile-press-scale": "How far a pressed tile sinks back.",
    "row-tilt": "A selectable row or entry tilts this far towards where it is pressed (a tile tilts tile-tilt): long and low, it needs less to read as a nudge. Degrees.",
    "row-press-scale": "How far a selectable row or entry sinks while pressed.",
    "duration-toast": "How long a toast stays, and the undo window it counts down in whole seconds (the source's 5). Wall time, not motion: it is never zeroed under reduced motion. Hover or focus on the toast holds it. Undo in a toast is a shortcut, never the only way back: the action stays reversible where its result went, so the window limits no function.",
    "duration-wheel-latch": "Wheel events closer than this form one gesture; a gesture latches to one scroller (panorama rule 1b).",
    "duration-tap-delay": "On touch, a tile presses only after this long without movement, so the start of a scroll never sinks it.",
    "duration-busy-delay": "A loading or pending indicator appears only after this long, so fast answers never flicker. Wall time: reduced motion leaves it alone.",
    "duration-busy-min": "Once a loading indicator shows, it stays at least this long, so it never flashes.",
    "duration-tip-delay": "A tooltip shows after the pointer has rested this long on its control (at once on keyboard focus, never on touch). Moving on to the next control within this time after one hid shows its tip at once.",
    "duration-long-press": "A touch held this long without moving opens a context menu, as a right click does.",
    "duration-stale": "A live region with no update or heartbeat for this long is stale: it says so, and its values stop looking current.",
    "layer-sticky": "Sticky strips inside a place (the section pivot on a phone).",
    "layer-appbar": "The bottom app bar.",
    "layer-banner": "The status banner.",
    "layer-toast": "The toast region, above the banner and the app bar.",
    "layer-float": "Floating surfaces (menus, lists) where the browser has no popover top layer. With popovers they sit in the top layer and need no value.",
    "bp-mobile": "Explicit design target width.",
    "bp-sideways-scroll-min": "Below this, navigation and panoramas never scroll sideways — only vertically.",
    "bp-short-height": "A viewport height. Up to this tall (400% zoom, a landscape phone) nothing sticks to the top: the status banner scrolls away with the page.",
    "bp-desktop": "Explicit design target width.",
    "bp-wide": "Explicit design target width.",
    "bp-ultrawide": "Explicit design target width."
  }
}
