/* GENERATED by tools/tokens/build.mjs from design-system/tokens/ui.tokens.json and tokens/components/*.tokens.json. Do not edit by hand. */
/* Fume UI tokens, DECIDED. Load tokens/fume-tokens.css first. */
:root {
  --ui-ground: var(--fume-porcelain); /* Default page ground. */
  --ui-ground-warm: var(--fume-paper); /* Whole sections only, never two in a row. */
  --ui-surface: var(--fume-focus-50); /* Cards and grouped content on Porcelain. A card never matches its ground. */
  --ui-surface-sunken: var(--fume-focus-100); /* Wells, inactive tracks, skeletons. */
  --ui-surface-sunken-hover: var(--fume-focus-200); /* Hover on a sunken surface (a switch track, a sunken badge): one step toward Ink. PROPOSED, round 7. */
  --ui-surface-creative: #FFFFFF; /* Pure white: only the customer's creative, inputs and the secondary button, always with a hairline (one of the few places a stroke is allowed). */
  --ui-text: var(--fume-focus-900); /* Primary text, 17.9:1 on Porcelain. */
  --ui-text-secondary: var(--fume-focus-700); /* Body and secondary text, 10.3:1. */
  --ui-text-tertiary: var(--fume-text-tertiary); /* Captions and meta, 5.8:1. Never lighter. */
  --ui-text-on-ink: var(--fume-paper); /* Text on Ink, 16.9:1. */
  --ui-text-disabled: var(--fume-focus-400); /* Disabled labels only. */
  --ui-hairline: var(--fume-border); /* Only where an element would otherwise vanish: input edges, the white secondary button, the edge of the customer's creative. Never between regions, panels, rows or a sidebar and the page (rule few-strokes). */
  --ui-hairline-strong: var(--fume-focus-300); /* Input edges on hover, secondary button on hover. */
  --ui-focus-ring: var(--fume-focus-900); /* Keyboard focus: a sharp 2px Ink ring, 2px off the edge. Never a soft halo. */
  --ui-focus-ring-on-glass: var(--fume-porcelain); /* Keyboard focus on glass. */
  --ui-check: var(--fume-amber); /* The Amber check. The checked triangle on work an expert has checked (each checked creative carries one), or a point beside a label. Never a fill, a button, text or an area bigger than a chip. */
  --ui-check-waiting: var(--fume-focus-500); /* The checked triangle on work that is still in check: the same shape as the Amber check, in grey (Marcus 13 Oct: Amber only when checked; the expert checks, only the customer approves). Always beside a text label, so colour is never the only signal. */
  --ui-selection: var(--fume-amber-100); /* Text selection highlight. */
  --ui-selected: rgb(245 158 86 / 0.1); /* Light on what you chose: a selected row, a date range. A faint wash of Amber, 10 % over the ground (#FEF4E9 on Porcelain), never full Amber and never a button; the control that chose it (the checkbox, the ends of the range) stays Ink. Round 10 (Marcus 13 Oct: Amber 50 was too much here); round 9 had Amber 50, round 8 Focus 100. The other candidate, Focus 100, is under $options.selection. */
  --ui-depth-near: rgb(27 20 16 / 0.06); /* Contact shadow for raised surfaces on light ground. */
  --ui-depth-far: rgb(27 20 16 / 0.08); /* Soft spread shadow for raised surfaces on light ground. */
  --ui-ground-behind: var(--fume-paper); /* The layer behind the page: app sidebars and rails sit on it, and the page lies on top as a Porcelain sheet. Paper, the warm ground the work lies on (DECIDED: Marcus chose Warmer, 13 Oct, round 9; round 8 had Focus 100). No stroke between them. Tertiary text 5.5:1. */
  --ui-behind-hover: var(--fume-cream); /* Rows on the layer behind (sidebar navigation): hover, one step warmer, Cream (DECIDED with Warmer, 13 Oct; round 8 had Focus 200). Tertiary text 4.9:1. */
  --ui-behind-active: var(--fume-porcelain); /* The current place in the sidebar comes forward to the page's own Porcelain, lifted with depth-raised. */
  --ui-danger: var(--fume-rouge); /* Rouge (Marcus, 13 Oct 2026, F-D067). Delete and errors. Paper label 4.7:1, as text on Porcelain 4.9:1. */
  --ui-danger-hover: var(--fume-rouge-deep); /* One step toward Ink. Paper label 5.7:1. */
  --ui-action-primary: var(--fume-focus-900); /* Ink: the first button. */
  --ui-action-primary-hover: var(--fume-focus-800); /* Ink lifts one step. */
  --ui-action-primary-pressed: var(--fume-focus-900); /* Returns to Ink; the press is carried by scale. */
  --ui-action-primary-fg: var(--fume-paper);
  --ui-action-secondary: #FFFFFF; /* White: the second button, with a hairline. */
  --ui-action-secondary-hover: var(--fume-focus-50); /* One step toward Ink. */
  --ui-action-secondary-pressed: var(--fume-focus-100); /* Two steps toward Ink. */
  --ui-action-secondary-edge: var(--fume-focus-200);
  --ui-action-secondary-edge-hover: var(--fume-focus-300);
  --ui-action-secondary-fg: var(--fume-focus-900);
  --ui-action-quiet: transparent; /* Ghost: no surface at rest. */
  --ui-action-quiet-hover: var(--fume-focus-100); /* One step. */
  --ui-action-quiet-pressed: var(--fume-focus-200); /* Two steps. */
  --ui-action-quiet-fg: var(--fume-focus-900);
  --ui-action-disabled: var(--fume-focus-100);
  --ui-action-disabled-fg: var(--fume-focus-400);
  --ui-glass-bg: rgb(27 20 16 / 0.28); /* Smoke (Marcus, 13 Oct 2026: Smoke, a little lighter). Ink at 28 % over a softened, dimmed backdrop: neutral warm grey, lighter and clearer than round 3. */
  --ui-glass-bg-solid: rgb(27 20 16 / 0.94); /* Fallback when blur is unsupported or transparency is reduced: solid Ink, never solid Brown. */
  --ui-glass-fg: var(--fume-porcelain); /* Text on glass. */
  --ui-glass-fg-secondary: rgb(255 253 249 / 0.88); /* Secondary text on glass, weight 500. 5.4:1 over the worst backdrop (a white page). Never thinner or fainter. */
  --ui-glass-scrim: rgb(27 20 16 / 0.28); /* Dims the page behind a modal (dim to focus). */
  --ui-glass-shadow-color: rgb(27 20 16 / 0.42);
  --ui-glass-shadow-color-near: rgb(27 20 16 / 0.2);
  --ui-glass-button-white: rgb(255 253 249 / 0.94); /* White button: the main action on glass. At least 90 % white so it reads solid. Ink label, 15:1. No shadow. */
  --ui-glass-button-white-hover: var(--fume-porcelain); /* Lifts to solid Porcelain. */
  --ui-glass-button-white-pressed: rgb(255 253 249 / 0.86); /* Sinks a little, with the 3 % shrink. */
  --ui-glass-button-white-fg: var(--fume-focus-900);
  --ui-glass-button-clear: rgb(255 253 249 / 0.1); /* Clear button: a faint Porcelain veil, so it is visibly there without a shadow or a stroke. Porcelain label 5.0:1 over the worst backdrop. Secondary actions on glass. */
  --ui-glass-button-clear-hover: rgb(255 253 249 / 0.14); /* Lifts one step. Porcelain label 4.6:1 over the worst backdrop. */
  --ui-glass-button-clear-pressed: var(--ui-glass-button-clear); /* Returns to rest, with the 3 % shrink. */
  --ui-glass-button-clear-fg: var(--fume-porcelain);
  --ui-glass-button-danger: rgb(186 74 82 / 0.8); /* Coloured buttons on glass have their own transparency: the colour at 80 %, so the glass shows through (Marcus 13 Oct). Danger is the only coloured button; Amber is never one. Porcelain label. No shadow, no stroke. */
  --ui-glass-button-danger-hover: rgb(186 74 82 / 0.9); /* Lifts to 90 %. */
  --ui-glass-button-danger-pressed: var(--ui-glass-button-danger); /* Returns to rest, with the 3 % shrink. */
  --ui-glass-button-danger-fg: var(--fume-porcelain);
  --ui-glass-button-disabled: rgb(255 253 249 / 0.06); /* Disabled button on glass, either variant. */
  --ui-glass-button-disabled-fg: rgb(255 253 249 / 0.45);
  --ui-glass-item-hover: var(--ui-glass-button-clear-hover); /* Menu rows on glass: hover and keyboard highlight. The row fills the menu edge to edge. */
  --ui-glass-field: rgb(255 253 249 / 0.12); /* Text fields on glass. No stroke; focus shows the ring. Label 4.8:1. */
  --ui-glass-filter: blur(20px) saturate(1.5) contrast(0.65) brightness(0.58); /* Smoke, lighter: the backdrop is softened (contrast 0.65) so dark images lift and light pages stay readable. Over a white page Porcelain text is 6.3:1, secondary text 5.4:1. */
  --ui-glass-filter-small: blur(14px) saturate(1.5) contrast(0.65) brightness(0.58); /* Small glass (tooltips, chips): the same material, thinner blur. */
  --ui-glass-shadow: 0 24px 48px -18px var(--ui-glass-shadow-color), 0 6px 14px -6px var(--ui-glass-shadow-color-near); /* Under the glass only: offset, Ink-tinted. No glow, no stroke, never on the buttons. */
  --ui-glass-shadow-small: 0 10px 24px -10px var(--ui-glass-shadow-color), 0 2px 6px -2px var(--ui-glass-shadow-color-near);
  --ui-depth-raised: 0 1px 2px var(--ui-depth-near), 0 2px 8px -2px var(--ui-depth-far); /* A surface lifted a little off its ground (the selected pill in a segmented control, a popover handle). Replaces a hairline. */
  --ui-depth-sheet: 0 1px 3px var(--ui-depth-near), 0 16px 40px -16px var(--ui-depth-far); /* The page as a sheet lying on the layer behind it (ground-behind). Replaces the stroke between a sidebar and the page. */
  --ui-radius-action: 999px; /* Pill: buttons, chips, badges, segmented controls, toolbars. DECIDED 12 Oct 2026 (Marcus). */
  --ui-radius-field: 12px; /* Inputs, selects, textareas. */
  --ui-radius-item: 10px; /* Rows in lists on light surfaces. Menu rows on glass have no radius of their own: they fill the menu and its corners clip them. */
  --ui-radius-check: 6px; /* Checkboxes: a 20 px box with a soft corner, half the field radius, so it keeps the softness of a field without turning into a circle. PROPOSED, round 7. */
  --ui-radius-card: var(--fume-radius-card); /* Cards and creative tiles: 16px. */
  --ui-radius-float: 22px; /* Menus, selects, popovers and tooltips: floating glass that is not a dialog. Rounder than cards. DECIDED 13 Oct 2026 (Marcus chose Rounder). */
  --ui-radius-panel: 32px; /* Dialogs, sheets, large glass panels. DECIDED 13 Oct 2026 (Marcus chose Rounder). */
  --ui-space-xs: var(--fume-space-1); /* 4px. Between a label and its hint. */
  --ui-space-sm: var(--fume-space-2); /* 8px. Icon to label in buttons; between buttons in a row. */
  --ui-space-md: var(--fume-space-3); /* 12px. Icon to label in menu rows; between a title and its text. */
  --ui-space-lg: var(--fume-space-4); /* 16px. Between groups inside a surface. */
  --ui-space-xl: var(--fume-space-5); /* 24px. Between a dialog's text and its buttons. */
  --ui-space-2xl: var(--fume-space-6); /* 32px. Between sections. */
  --ui-inset-panel: var(--fume-space-5); /* 24px. Dialogs, sheets and glass panels with text (radius.panel 32). */
  --ui-inset-float: var(--fume-space-4); /* 16px. Popovers, cards and toasts with text, and sideways in menu and list rows (radius.float 22). */
  --ui-inset-tight: var(--fume-space-3); /* 12px. Sideways in tooltips and small glass labels. */
  --ui-inset-ring: 6px; /* The even gap between a pill bar and the pills inside it, so the inner pill follows the outer one. */
  --ui-inset-seg: 3px; /* Gap between a segmented track and its white pill. Round 6 choice: inset (3px) or fill (0, the pill fills the track); see $options.segmented. */
  --ui-type-family: var(--fume-font-text); /* GT Standard. The only UI face. */
  --ui-type-family-data: var(--fume-font-mono); /* GT Standard Mono: timestamps, sizes, codes, keyboard keys. Never as decoration. */
  --ui-type-label: var(--fume-type-label); /* 12px, weight 500, +0.01em. */
  --ui-type-control: var(--fume-type-small); /* 14px: buttons, inputs, menu items. */
  --ui-type-body: var(--fume-type-body); /* 16px. */
  --ui-type-body-large: var(--fume-type-body-l); /* 18px. */
  --ui-type-title: var(--fume-type-heading); /* 24px, weight 500, -0.015em. GT Standard, not Canon. */
  --ui-type-title-large: var(--fume-type-title); /* 32px, weight 500, -0.02em. GT Standard, not Canon. */
  --ui-type-display: var(--fume-type-display-m); /* 52px, GT Canon, weight 500, -0.02em. Marketing titles only (the brand book's page titles, the website, decks); never in the product. Each use marks gate-allow:canon-not-in-ui. */
  --ui-type-display-hero: var(--fume-type-display-l); /* 72px, GT Canon, weight 400, -0.02em. The one title that leads the first view of a web page (kit/web.css .web-display--hero). Marketing only; each use marks gate-allow:canon-not-in-ui. */
  --ui-type-display-small: var(--fume-type-title); /* 32px, GT Canon. Marketing titles on a phone (under 760 px), so a title keeps to three or four lines at 390 px (kit/web.css). */
  --ui-type-display-family: var(--fume-font-display); /* GT Canon (Newsreader stands in on trial licences). Only with --ui-type-display, for marketing titles; the gate flags every use (canon-not-in-ui) so each one is marked. */
  --ui-type-weight-regular: 400;
  --ui-type-weight-medium: 500;
  --ui-size-control-sm: 32px;
  --ui-size-control-md: 40px;
  --ui-size-control-lg: 48px; /* Touch and marketing. */
  --ui-size-seg: 36px; /* Height of a segmented track (tabs, filters). The options are this minus twice inset.seg. */
  --ui-size-hit: 44px; /* The smallest touch target (Apple HIG 44 pt, WCAG 2.5.5). A control may look smaller (32 px small buttons, 30 px tab pills) but its hit area is never under this. */
  --ui-size-icon-sm: 14px;
  --ui-size-icon: 16px;
  --ui-size-icon-lg: 18px;
  --ui-size-icon-stroke: 2.25; /* Line-only icons (check, plus, x, arrows, search). Every other icon is filled (DECIDED 13 Oct). Built in design-system/icons. */
  --ui-size-pad-sm: 14px;
  --ui-size-pad-md: 18px;
  --ui-size-pad-lg: 24px;
  --ui-size-ring: 2px;
  --ui-size-ring-offset: 2px;
  --ui-motion-instant: 100ms; /* Press feedback, on pointer-down. */
  --ui-motion-fast: 160ms; /* Hover and colour changes. */
  --ui-motion-base: 240ms; /* Glass materialising, small layout changes. */
  --ui-motion-slow: 480ms; /* Large surfaces. */
  --ui-motion-ease: cubic-bezier(.2, 0, 0, 1); /* ease.focus: soft to sharp. */
  --ui-motion-press-scale: 0.97;
  --ui-motion-enter-blur: 8px; /* Glass arrives from blur to sharp. */
  --ui-motion-enter-scale: 0.98;
  --ui-motion-spin: 900ms; /* One turn of the loading spinner. */
  --ui-motion-spin-reduced: 2400ms; /* Spinner under reduced motion. */
  --ui-motion-slide: 280ms; /* Tabs and segmented controls: the selection slides to the new option. Easing gets its own round. */
  --ui-book-page: 1120px; /* Widest the page content gets beside the contents rail: figures and specimens use it all. */
  --ui-book-measure: 68ch; /* The reading column: running text never runs wider than 68 characters. */
  --ui-book-lede: 56ch; /* The page's opening line under its title. */
  --ui-book-toc: 200px; /* The contents rail on the right (On this page), shown from 1280 px. */
  --ui-book-bar: var(--ui-size-control-lg); /* Height of the bar at the top of the page sheet: the drawer button on a phone, where you are, Search. */
  --ui-book-figure-min: 240px; /* Smallest a specimen tile gets before the grid drops a column. */
  --ui-book-swatch: 96px; /* Height of a colour swatch's colour field. */
  --ui-book-logo-stage: 280px; /* Height of a logo stage: the logo sits in the middle with its clear space around it. */
  --ui-chart-series-1: var(--fume-focus-900); /* The first series: Ink. 17.9:1 on Porcelain, 16.9:1 on a card. Series take their colour in this fixed order and keep it when others are hidden (colour follows the series, never its rank). Never Amber. */
  --ui-chart-series-2: var(--fume-focus-600); /* The second series: Focus 600. 6.8:1 on Porcelain, 6.4:1 on a card; 27 apart from Ink (OKLab x100), so the two read apart at a glance and in greyscale. */
  --ui-chart-series-3: var(--fume-focus-400); /* The third series: Focus 400. 2.6:1 on Porcelain, under 3:1, so it never stands alone: it sits beside a darker series behind a 2 px gap, and the legend, a direct label and the table name it. 23 apart from Focus 600. */
  --ui-chart-series-4: var(--fume-focus-200); /* The fourth and last series: Focus 200 (1.4:1), for an Other slice or the rest of a whole, always labelled. A fifth series folds into Other; Fume never makes up a fifth colour. */
  --ui-chart-approved: var(--fume-amber); /* Checked work in a chart: full Amber, the colour of the check (decided with Warmer, Marcus 13 Oct; round 9, Marcus 13 Oct: more Amber). Only for a series that counts approvals (approved per week, first-pass approval), never for any other series; Generated beside it stays Ink. 2.1:1 on Porcelain, so like series 3 it never stands alone: it is named in the legend and at the end of its line, and its values are in words and in the tooltip. */
  --ui-chart-area-opacity: 0.08; /* An area is its series colour at 8 %, flat: a wash under the line, never a gradient and never a block. Where two areas overlap the wash doubles, so the band between Generated and Approved reads on its own. */
  --ui-chart-tick: var(--ui-text-tertiary); /* Axis ticks, dates and category names: tertiary text, 5.8:1. Ticks are words only: no axis line, no tick marks, no gridlines. */
  --ui-chart-label: var(--ui-text-secondary); /* Direct labels on the marks (the last value of a line, the total on a column): secondary text, 10.3:1. Text never wears a series colour. */
  --ui-chart-baseline: var(--ui-hairline); /* The one line a chart may draw: a hairline at zero under vertical bars, because columns of different heights otherwise float as loose blocks above their names, and a zero (Travel Minis has no Banners) needs a floor to read as zero. Lines, areas, rows and donuts have none. */
  --ui-chart-cursor: rgb(27 20 16 / 0.05); /* The point under the pointer or the keyboard: a soft band behind that week or that column (Ink at 5 %), radius item. A surface, not a crosshair line. With the keyboard it carries the 2 px focus ring. */
  --ui-chart-dim: 0.32; /* Opacity of the other slices while one donut slice is active, so the active one comes into focus. */
  --ui-chart-gap: 2px; /* The surface gap between touching marks: stacked segments, bars side by side in a group and donut slices. Space separates them, never a stroke around a mark. */
  --ui-chart-bar-max: 24px; /* The widest a column gets. The rest of its slot stays air. */
  --ui-chart-bar-grouped: 16px; /* Each column in a group of three: 16 + 2 + 16 + 2 + 16, so a group is about twice a stacked column. */
  --ui-chart-bar-row: 12px; /* A bar in the row layout (ranking, and every bar chart on a phone): 12 tall under its name, 8 below it. A ranking bar is a pill on a sunken track that runs to 100 %. */
  --ui-chart-bar-radius: 4px; /* The data end of a bar is rounded 4 px; the end at the baseline stays square, so every bar visibly grows from the same zero. Only the top segment of a stack is rounded. */
  --ui-chart-track: var(--ui-surface-sunken); /* The track behind a ranking bar, to 100 %. Inside a card it steps one deeper (track-on-surface), like a progress bar in a card. */
  --ui-chart-track-on-surface: var(--ui-card-progress-track); /* The ranking track inside a card: Focus 200, so it reads on the card surface without a line. */
  --ui-chart-line: 2px; /* A line is 2 px, round caps and joins, drawn on a monotone curve (it never overshoots a value). */
  --ui-chart-point: 8px; /* A point (the last value of a line, the point under the pointer): an 8 px dot in the series colour with a 2 px ring in the ground colour, so it stays clear where it crosses a line. */
  --ui-chart-height: 240px; /* The default chart height, axis band included, so a card never needs its own scroll. */
  --ui-chart-height-compact: 200px; /* The height on a phone and in a half-width card. */
  --ui-chart-tick-gap: var(--ui-space-sm); /* 8 px between the plot and its tick labels, and between a mark and its direct label. */
  --ui-chart-donut: 176px; /* The donut's diameter. The total sits in the middle in the data type. */
  --ui-chart-donut-ring: 20px; /* The donut's ring: thin enough to read as a whole, with 2 px gaps between slices. */
  --ui-chart-draw: var(--ui-motion-slow); /* The draw-in when a chart first comes into view: lines draw from the left, bars grow from the baseline, the donut sweeps round, in 480 ms. With reduced motion the chart is simply there. */
  --ui-chart-stagger: calc(var(--ui-motion-instant) / 4); /* 25 ms between columns as they grow, so the draw-in travels across the chart like light. */
  --ui-chart-tooltip-width: 168px; /* The least width of the chart tooltip: Smoke glass at radius float with 16 px air (it holds several lines, so it is a small panel, not tooltip.css's one-line pill). The date on top, then one row per series: the name in secondary, the value in the data type. No colour keys: on Smoke glass every Focus step but Ink sinks into the glass, so the names carry identity and the chart's active points carry the colour. */
  --ui-stat-min: 132px; /* The narrowest a stat tile gets: a row of four on a desktop, two by two on a phone. */
  --ui-stat-gap: var(--ui-space-lg); /* 16 px between tiles in a row. */
  --ui-stat-spark: 40px; /* The height of a tile's sparkline. It spans the tile, 16 below the comparison, and ends in a dot on the latest value. */
  --ui-stat-spark-line: var(--ui-chart-series-1); /* The sparkline is Ink, 2 px, with its area wash. Never a trend colour: up and down are said in words beside the trend icon. */
  --ui-stat-empty: var(--ui-surface-sunken-hover); /* An empty tile draws its sparkline as a flat line in Focus 200 along zero: the shape of nothing yet, not a missing chart. */
  --ui-legend-swatch: var(--ui-chart-point); /* The key beside a series name: an 8 px dot, the same as the chart's points. */
  --ui-legend-height: var(--ui-size-control-sm); /* A legend item is a 32 px pill toggle with a 44 px hit area. At rest it has no surface (dot and name only); hover and press bring up the quiet pill. */
  --ui-legend-off: var(--ui-surface-sunken-hover); /* The key of a hidden series turns Focus 200 and its name tertiary; aria-pressed says it, so colour is never the only signal. The axis never moves when a series is hidden. */
  --ui-check-size: 20px; /* The checkbox and the radio: a 20 px box, centred in a 44 px hit area (size.hit). */
  --ui-check-bg: var(--ui-surface-creative); /* Unchecked checkbox and radio: white, like an input, with the edge below. */
  --ui-check-edge: rgb(27 20 16 / 0.48); /* The hairline of an unchecked box or circle: Ink at 48 %, 3.2:1 on white and 3.0:1 against a card, so the 20 px control passes the 3:1 for UI parts. Lighter hairlines (Border, Focus 300) vanish at this size. One of the few strokes the system allows: without it the box disappears. */
  --ui-check-edge-hover: rgb(27 20 16 / 0.72); /* Hover: the edge comes one step toward Ink. */
  --ui-check-on: var(--ui-action-primary); /* Checked, indeterminate and selected: Ink. Never Amber. */
  --ui-check-on-hover: var(--ui-action-primary-hover); /* Checked under the pointer: Ink lifts one step, like the primary button. */
  --ui-check-mark: var(--fume-porcelain); /* The check, the dash and the radio's centre on Ink: Porcelain, 17.9:1. */
  --ui-check-ring: 6px; /* A selected radio: the edge thickens into a 6 px Ink ring around an 8 px Porcelain centre. */
  --ui-check-disabled: var(--ui-action-disabled); /* Disabled box or circle, checked or not: the sunken disabled surface, no edge. */
  --ui-check-disabled-mark: var(--ui-action-disabled-fg); /* The check, dash or centre on a disabled control. */
  --ui-switch-width: 40px; /* Default switch track: 40 x 24, a pill. The hit area is 44 either way. */
  --ui-switch-height: 24px;
  --ui-switch-thumb: 20px; /* The white thumb, 2 px inside the track. */
  --ui-switch-width-sm: 32px; /* Small switch, for dense rows and glass: 32 x 20. */
  --ui-switch-height-sm: 20px;
  --ui-switch-thumb-sm: 16px;
  --ui-switch-stretch: 4px; /* Pressed: the thumb stretches 4 px toward where it will go, the moment the finger lands. */
  --ui-switch-track: var(--ui-surface-sunken); /* Off: the sunken surface. The white thumb, lifted by depth, carries the shape. */
  --ui-switch-track-hover: var(--ui-surface-sunken-hover); /* Off under the pointer: one step toward Ink. */
  --ui-switch-track-on: var(--ui-action-primary); /* On: Ink decides. Never Amber. */
  --ui-switch-track-on-hover: var(--ui-action-primary-hover); /* On under the pointer: Ink lifts one step. */
  --ui-switch-track-on-disabled: var(--fume-focus-300); /* On and disabled: Ink falls back to Focus 300, so on and off stay apart without looking active. */
  --ui-switch-thumb-bg: var(--ui-action-secondary); /* The thumb: white, lifted with depth.raised instead of an edge. */
  --ui-switch-thumb-disabled: var(--ui-surface); /* Disabled thumb: Focus 50, flat. */
  --ui-switch-glass-track: rgb(255 253 249 / 0.18); /* Off on glass: a Porcelain veil, a little stronger than the clear button's so the track reads at 20 px. */
  --ui-switch-glass-track-hover: rgb(255 253 249 / 0.26); /* Off on glass under the pointer: the veil lifts one step. */
  --ui-switch-glass-track-on: var(--ui-glass-button-white); /* On on glass: the white of the main glass button. The thumb turns Ink, so on reads at a glance over any photo. */
  --ui-switch-glass-thumb: var(--fume-porcelain); /* The thumb on glass when off. No shadow on glass. */
  --ui-switch-glass-thumb-on: var(--ui-action-primary); /* The thumb on glass when on: Ink on white. */
  --ui-slider-track-height: 4px; /* A thin pill track. */
  --ui-slider-thumb: 20px; /* The white thumb, lifted with depth.raised; its hit area is 44. */
  --ui-slider-track: var(--ui-surface-sunken); /* The track outside the range. */
  --ui-slider-range: var(--ui-action-primary); /* The chosen range: Ink. Never Amber. */
  --ui-slider-range-disabled: var(--fume-focus-300); /* The range on a disabled slider. */
  --ui-slider-thumb-bg: var(--ui-action-secondary); /* White, like the switch thumb. */
  --ui-slider-glass-track: rgb(255 253 249 / 0.2); /* The track on glass: a Porcelain veil. */
  --ui-slider-glass-range: var(--fume-porcelain); /* The range and the thumb on glass: Porcelain. No shadow on glass. */
  --ui-progress-height: 4px; /* A thin pill track, the same weight as the slider's. */
  --ui-progress-track: var(--ui-surface-sunken);
  --ui-progress-fill: var(--ui-action-primary); /* Ink. Never Amber: progress is work under way, Amber is work checked. */
  --ui-progress-sweep: calc(var(--ui-motion-spin) * 2); /* 1800 ms: one pass of the indeterminate bar, two spinner turns. */
  --ui-progress-glass-track: rgb(255 253 249 / 0.2); /* The track on glass: a Porcelain veil. */
  --ui-progress-glass-fill: var(--fume-porcelain); /* The fill on glass: Porcelain. */
  --ui-badge-height: 24px; /* A badge: a 24 px pill with 12 px label text and 12 px air at the ends. */
  --ui-badge-height-sm: 20px; /* Counts beside a label or in a row. */
  --ui-badge-dot: 6px; /* The status dot beside a badge label, and the dot on an icon. */
  --ui-badge-hover: var(--ui-surface-sunken-hover); /* A neutral badge that is a link or a button, under the pointer: one step toward Ink from the sunken surface. */
  --ui-badge-pressed: var(--fume-focus-300); /* The same badge pressed: two steps, with the 3 % shrink. */
  --ui-spinner-size-xl: 24px; /* The display spinner, for a page or a panel that is loading. Controls use the icon sizes (14, 16, 18). */
  --ui-card-bg: var(--ui-surface); /* A card is one surface step off its Porcelain ground, never the same colour (card-never-matches-ground). No border and no shadow at rest: the step is the edge. */
  --ui-card-bg-hover: var(--fume-focus-100); /* Interactive card, hover: one more step toward Ink. */
  --ui-card-bg-pressed: var(--fume-focus-100); /* Interactive card, pressed: stays on the hover step and shrinks (card.press-scale), so a large surface never flashes dark. */
  --ui-card-bg-behind: var(--ui-ground); /* On the layer behind the page (ground-behind) a card comes forward to Porcelain, like the page sheet itself. */
  --ui-card-depth-behind-hover: var(--ui-depth-raised); /* On the layer behind, Porcelain is already the top step, so an interactive card lifts with depth instead of a darker surface. */
  --ui-card-press-scale: 0.985; /* A card is wide, so it shrinks half as much as a button (0.97) for the press to read the same. */
  --ui-card-progress-track: var(--fume-focus-200); /* Track of a progress bar inside a card (the campaign card's approvals): one step deeper than progress.track, so it reads on the card surface without a line. The fill stays Ink (progress.css); never Amber. */
  --ui-creative-bg: var(--ui-surface-creative); /* The customer's creative sits on pure white: the one content surface allowed to be white. */
  --ui-creative-edge: rgb(27 20 16 / 0.1); /* The creative's hairline, drawn over the image: Ink at 10 %, so a white creative keeps its edge on Porcelain and a dark one gets no light rim. The one content stroke Fume allows (few-strokes). */
  --ui-creative-ratio-feed: 4 / 5; /* Feed format. */
  --ui-creative-ratio-story: 9 / 16; /* Story format. */
  --ui-creative-ratio-banner: 1.91 / 1; /* Banner format (link and display ads). */
  --ui-creative-ring: var(--ui-action-primary); /* Selected creative: an Ink ring, 2 px, 2 px off the creative (Ink decides). Never Amber. */
  --ui-creative-badge: var(--ui-action-primary); /* The round select badge on a selected creative: Ink with a Paper check. */
  --ui-creative-badge-fg: var(--ui-action-primary-fg);
  --ui-creative-badge-size: 24px; /* Select badge diameter. */
  --ui-creative-tile-min: 128px; /* Smallest tile in a creative grid; the grid fills the row with as many as fit (two on a phone, even inside a padded panel). */
  --ui-item-bg-hover: var(--ui-action-quiet-hover); /* A row you can press: hover is one step toward Ink, like a quiet button. No lines between rows; rows are grouped by space. */
  --ui-item-bg-pressed: var(--ui-action-quiet-pressed); /* Two steps toward Ink. */
  --ui-item-bg-muted: var(--ui-surface); /* The muted row (shadcn variant muted, and outline, which Fume draws as a surface instead of a border). */
  --ui-item-media: 40px; /* Media width in a default row: icon tile, avatar or a creative thumbnail (4:5, so 50 tall). */
  --ui-item-media-sm: 32px; /* Media width in a small row. */
  --ui-avatar-size-sm: 24px;
  --ui-avatar-size: 32px;
  --ui-avatar-size-lg: 40px;
  --ui-avatar-bg: var(--fume-cream); /* Initials on Cream, Ink text in medium weight (15.0:1): people are the real, the Material family (decided with Warmer, Marcus 13 Oct; round 9; round 8 had the sunken step). */
  --ui-avatar-fg: var(--ui-text);
  --ui-avatar-bg-ink: var(--ui-action-primary); /* The person you are (or the one who decides, Anna on a check): Ink with Paper initials. */
  --ui-avatar-fg-ink: var(--ui-text-on-ink);
  --ui-avatar-cutout: 2px; /* The gap that separates overlapping avatars and the status dot from the avatar under them. Painted in the ground colour, so it reads as space cut out of the circle, not as a line. */
  --ui-avatar-status: var(--ui-text); /* Status dot: here now, in Ink. No green; Fume has no success colour. */
  --ui-avatar-status-away: var(--ui-text-disabled); /* Status dot: away. */
  --ui-alert-bg: var(--ui-surface); /* An inline alert is a surface step on its ground, never a bordered box. Info, success and warning differ by icon and words, not by colour. */
  --ui-alert-bg-on-surface: var(--ui-surface-sunken); /* Inside a card the alert steps one further, so it never matches its ground. */
  --ui-alert-danger: var(--ui-danger); /* Error alerts: Rouge on the icon and the title only. The text stays secondary. */
  --ui-alert-bg-glass: var(--ui-glass-button-clear); /* An alert on glass (inside a dialog or sheet): the faint Porcelain veil, no stroke. */
  --ui-alert-bg-glass-danger: var(--ui-glass-button-danger); /* An error alert on glass is Rouge at 80 %, like the delete button on glass: Rouge as an icon colour disappears on Smoke (1.3:1). Porcelain text 5:1. */
  --ui-empty-media: 56px; /* The soft square that holds the empty state's 24 px icon. */
  --ui-empty-media-bg: var(--ui-surface-sunken);
  --ui-empty-measure: 38ch; /* Line length of the empty state's text: short lines, centred. */
  --ui-empty-icon: 24px; /* The empty state's icon at display size (icons-lucide: 24 px for display). */
  --ui-skeleton-bg: var(--ui-surface-sunken); /* Placeholder shapes on Porcelain: the sunken step, in the shape and size of what is coming. */
  --ui-skeleton-bg-pulse: var(--ui-surface); /* The shimmer lifts the shape to the surface step and back, slowly. A flat colour change, never a gradient sweep (round 7; restored in round 9 after Marcus found the round 8 sweep artificial). */
  --ui-skeleton-bg-on-surface: var(--fume-focus-100); /* Inside a card (surface) the shape starts one step deeper... */
  --ui-skeleton-bg-pulse-on-surface: var(--fume-focus-200); /* ...and pulses a step toward Ink, so it never vanishes into the card. */
  --ui-skeleton-bg-glass: var(--ui-glass-button-clear); /* A shape on glass (a sheet or popover while it loads): the faint Porcelain veil of the clear button, no stroke. */
  --ui-skeleton-bg-pulse-glass: rgb(255 253 249 / 0.18); /* On glass the shape breathes from the 10 % veil to Porcelain at 18 % and back: one step lighter, never Amber on Smoke. */
  --ui-accordion-bg: var(--ui-surface); /* Each section is its own surface; sections are separated by space (accordion.gap), never a line. */
  --ui-accordion-bg-hover: var(--fume-focus-100); /* Hover on a section's trigger steps the whole section toward Ink. */
  --ui-accordion-gap: var(--ui-space-sm); /* Space between sections. */
  --ui-accordion-row: 56px; /* Height of a trigger row: a calm, generous target (44 px at least, rule touch-target). */
  --ui-scroll-thumb: rgb(27 20 16 / 0.2); /* Scroll-area thumb at rest: a thin pill of Ink at 20 %, laid over the content's edge. No track, no line. */
  --ui-scroll-thumb-hover: rgb(27 20 16 / 0.36); /* Thumb under the pointer or while dragged: one step more Ink. */
  --ui-scroll-size: 6px; /* Thumb thickness. */
  --ui-scroll-size-hover: 8px; /* Thumb thickness under the pointer, easier to grab. */
  --ui-datalist-label: var(--ui-text-tertiary); /* Metadata label (Format, Size, Checked by): tertiary, so the value leads. */
  --ui-datalist-text: var(--ui-text); /* Metadata value. (Named text: a group key called value would read as a token.) */
  --ui-datalist-label-width: 112px; /* Label column in the side-by-side data list; values align on one edge. Below 320 px the label goes above its value. */
  --ui-datalist-cell: 80px; /* Smallest cell in the grid data list (.ui-datalist--grid): a stat strip wraps to two columns on a phone and four in a wide card. */
  --ui-text-shimmer-light: #FFFFFF; /* White light passing through dark words while something is under way. It only ever passes; the words rest in their own colour. Round 11 (Marcus 13 Oct: 'Shimmer skal være hvit på mørk tekst'); round 10 had Amber. The Engine's words take the same white light since 15 Oct (Marcus: 'amber shimmer var ikke fint'). */
  --ui-text-shimmer-strength: 75%; /* How far the words go toward the light at the middle of the band: three quarters of the way to white, a gleam, so Ink words never vanish into the Porcelain page. */
  --ui-text-shimmer-band: 16%; /* Width of the band of light, as a share of the gradient strip (2.5 × the text), so about 40 % of a short line. */
  --ui-text-shimmer-duration: 2600ms; /* One pass and a rest: the light crosses in the first 70 % and the words rest for the last 30 %. */
  --ui-text-shimmer-angle: 100deg; /* The band leans a little, like light through a window, not a vertical bar. */
  --ui-message-bubble: var(--ui-surface-sunken); /* A person's message sits in a bubble one surface step toward Ink. The Engine has no bubble: it speaks as plain text on the page with its mark, so a person and the Engine never look alike. */
  --ui-message-bubble-fg: var(--ui-text); /* Text in a bubble and the Engine's text: Ink, 16 px, for reading. */
  --ui-message-mention: var(--fume-focus-200); /* An @mention inside a bubble: one more step toward Ink than the bubble, Ink text in medium weight. No colour of its own. */
  --ui-message-measure: 64ch; /* The longest line in a message, so the Engine's text reads like a column, never a banner. */
  --ui-message-bubble-max: 85%; /* A bubble never runs the full width: it leaves room on the other side, so who said it reads at a glance. */
  --ui-message-gap: var(--ui-space-xl); /* Between messages from different senders (24). */
  --ui-message-group-gap: var(--ui-space-xs); /* Between consecutive messages from one sender (4): they read as one turn (rule proximity: 4 inside, 24 between). */
  --ui-message-head-gap: var(--ui-space-sm); /* From a sender's name to what they said (8). */
  --ui-message-sign: 24px; /* The sender's sign beside the name: a 24 px avatar for a person, the Engine mark at 18 in the same box. It sits in the header, so bubbles and the Engine's text share one left edge. */
  --ui-message-caret: var(--ui-text); /* The quiet caret after text that is still arriving: an Ink bar, 2 px wide, one line tall, fading slowly in and out. */
  --ui-message-caret-width: 2px;
  --ui-message-think-scale: 0.72; /* Thinking: the Engine mark's focal point breathes between this size and full size inside its still frame corners (soft to sharp). No shimmer, no gradient. */
  --ui-message-scroller-height: 560px; /* Default height of a message scroller on the board. In the product it fills its pane. */
  --ui-message-scroller-pill-offset: var(--ui-space-lg); /* The jump-to-latest pill floats this far above the bottom of the conversation. */
  --ui-composer-bg: var(--ui-field-bg); /* The brief composer is a field: white with the field's hairline. */
  --ui-composer-edge: var(--ui-field-edge);
  --ui-composer-edge-hover: var(--ui-field-edge-hover);
  --ui-composer-edge-invalid: var(--ui-field-edge-invalid); /* Over the limit: a Rouge edge, the count in Rouge and a sentence that says how much to cut. */
  --ui-composer-bg-disabled: var(--ui-field-bg-disabled);
  --ui-composer-chip: var(--ui-surface-sunken); /* Chips inside the white composer (Brand DNA, the count, formats that are off): the sunken step. Formats that are on are Ink. */
  --ui-composer-chip-hover: var(--ui-surface-sunken-hover);
  --ui-composer-chip-pressed: var(--fume-focus-300);
  --ui-composer-chip-glass: var(--ui-glass-button-clear); /* Chips on the glass composer: the clear veil. The send button is the one white thing on the glass. */
  --ui-composer-chip-glass-on: var(--ui-glass-button-clear-hover); /* A format that is on, on glass: one veil step up and a check before the word, so it never needs a second white pill. */
  --ui-composer-input-min: 48px; /* The brief starts two lines tall (16 px text) and grows with what is written. */
  --ui-composer-input-max: 240px; /* After ten lines the brief scrolls inside the composer, so the conversation stays in view. */
  --ui-composer-width: 720px; /* The widest a composer gets on a desktop: the conversation's column. */
  --ui-composer-swap-scale: 0.6; /* Send turns into stop in place: one icon shrinks and fades as the other grows in, inside the same Ink circle. */
  --ui-composer-safe: env(safe-area-inset-bottom, 0px); /* The phone's safe area under a docked composer (the home indicator). The dock keeps at least 8 below the composer, or this, whichever is more. */
  --ui-run-indicator: 20px; /* The column of step signs: a check when done, the spinner while running, a grey checked triangle while it waits for Anna. No line joins them: steps are parted by space. */
  --ui-run-pending: var(--fume-focus-300); /* The small dot of a step that has not started. */
  --ui-run-slot: var(--ui-ground); /* A creative that is not made yet: a still Porcelain slot in the run card, lighter than the card and quieter than the one being made (which breathes on the sunken step), in the shape of the creative to come. */
  --ui-run-tile-cols: 6; /* Creatives per row in the run card (12 in two rows). */
  --ui-run-tile-cols-narrow: 4; /* Creatives per row on a phone (12 in three rows). */
  --ui-run-step-gap: var(--ui-space-lg); /* Between steps (16); inside a step its parts sit 4 to 8 apart. */
  --ui-attachment-bg: var(--ui-surface); /* An attachment is one surface step off its ground, like a small card: no border, no dashes. */
  --ui-attachment-bg-hover: var(--fume-focus-100);
  --ui-attachment-bg-pressed: var(--fume-focus-200);
  --ui-attachment-bg-on-surface: var(--ui-surface-sunken); /* Inside a card, a run or a bubble it steps once more, so it never matches its ground. */
  --ui-attachment-bg-glass: var(--ui-glass-button-clear); /* On the glass composer: the clear veil, Porcelain text. */
  --ui-attachment-media: 40px; /* Thumbnail in a horizontal attachment, 6 in from the edge (inset.ring) with radius 10, so its corner follows the attachment's 16. */
  --ui-attachment-media-tile: var(--ui-surface-sunken); /* The tile behind a brief's page icon (file-text). */
  --ui-attachment-max: 320px; /* The widest a horizontal attachment gets; a long name is cut with an ellipsis and read in full by screen readers. */
  --ui-attachment-card: 120px; /* Width of a vertical attachment: the creative at its own format on top, name and data under it. */
  --ui-marker-fg: var(--ui-text-tertiary); /* A quiet marker (read up to here, a day, done): tertiary words with space around them, never a line. */
  --ui-marker-fg-new: var(--ui-text); /* New since you left: Ink words, an Ink dot and the count. */
  --ui-marker-dot: var(--ui-text);
  --ui-marker-dot-size: var(--ui-badge-dot);
  --ui-marker-before: var(--ui-space-2xl); /* Space above a marker (32): more than below it, so the marker belongs to what follows. */
  --ui-marker-after: var(--ui-space-lg); /* Space below a marker (16). */
  --ui-field-bg: var(--ui-surface-creative); /* White. A field is one of the three white things in Fume (with the creative and the secondary button), always with its hairline. */
  --ui-field-edge: var(--ui-action-secondary-edge); /* The hairline at rest: the same edge as the white secondary button, so a field and the button beside it read as one family. The only stroke a field has (rule few-strokes allows it: without it a white field vanishes on Porcelain). */
  --ui-field-edge-hover: var(--ui-hairline-strong); /* Hover with a mouse: the hairline steps toward Ink. Never a fill change. */
  --ui-field-edge-invalid: var(--ui-danger); /* Rouge edge on a field that holds an error, always with a message in words under it. */
  --ui-field-fg: var(--ui-text); /* The value: Ink. */
  --ui-field-placeholder: var(--ui-text-tertiary); /* Placeholder and addon text (https://, kr): 5.8:1, never lighter. */
  --ui-field-icon: var(--ui-text-tertiary); /* Icons inside a field (search, chevrons, paperclip). */
  --ui-field-bg-pressed: var(--ui-action-secondary-hover); /* A select trigger or a choice card while it is pressed: one step toward Ink, like the white button. */
  --ui-field-bg-readonly: var(--ui-surface); /* Read-only: the value sits in the page instead of on it. No hairline, full Ink text, still selectable and focusable. */
  --ui-field-bg-disabled: var(--ui-action-disabled); /* Disabled: sunken like a disabled button, no hairline. */
  --ui-field-fg-disabled: var(--ui-text-disabled); /* Text in a disabled field and its label. */
  --ui-field-error: var(--ui-danger); /* The error message under a field: Rouge, weight 500, after the circle-alert icon. 4.9:1 on Porcelain. */
  --ui-field-height-sm: var(--ui-size-control-sm); /* 32 px. Dense tables and toolbars, with a mouse only: 44 on touch screens. */
  --ui-field-height: var(--ui-size-control-md); /* 40 px, the default field. On touch screens every field is --ui-size-hit (44) tall with 16 px text (rules touch-target, fields-16-on-touch). */
  --ui-field-height-lg: var(--ui-size-control-lg); /* 48 px, with 16 px text: sign-in and marketing forms. */
  --ui-field-pad: var(--ui-size-pad-sm); /* 14 px from the field's edge to its text, more than three quarters of the 12 px corner. */
  --ui-field-pad-sm: var(--ui-space-md); /* 12 px in the small field. */
  --ui-field-pad-lg: var(--ui-inset-float); /* 16 px in the large field. */
  --ui-field-pad-block: var(--ui-space-md); /* 12 px above and below the text in a textarea. */
  --ui-field-textarea-min: 96px; /* A textarea starts at three lines and grows with its text. */
  --ui-field-textarea-max: 280px; /* Where a growing textarea stops and scrolls. */
  --ui-field-list-max: 320px; /* The tallest an open select listbox gets before it scrolls (less when the window is shorter): about seven rows. */
  --ui-field-gap-label: var(--ui-space-sm); /* 8 px from a label down to its control (rule proximity). */
  --ui-field-gap-hint: var(--ui-space-xs); /* 4 px from a control down to its description or error: they belong to it. */
  --ui-field-gap: var(--ui-space-xl); /* 24 px between fields: three times the label gap, so every label clearly belongs to the field under it. */
  --ui-field-gap-group: var(--ui-space-2xl); /* 32 px between field sets (groups of fields). */
  --ui-field-gap-legend: var(--ui-space-lg); /* 16 px from a field set's legend (and its description) to its first field. */
  --ui-field-glass-bg: var(--ui-glass-field); /* A field on glass: a faint Porcelain veil, no stroke. Focus shows the Porcelain ring. */
  --ui-field-glass-fg: var(--ui-glass-fg); /* The value on glass. */
  --ui-field-glass-placeholder: var(--ui-glass-fg-secondary); /* Placeholder, icons and addons on glass: 88 % Porcelain, weight 500. */
  --ui-field-glass-edge-invalid: var(--ui-danger); /* Round 8. A field on glass that holds an error: a 2 px band of solid Rouge just inside a 1 px Porcelain rim (--ui-field-glass-edge-invalid-rim). Rouge alone against Smoke measured 1.3:1 over a white page and 2.5:1 over the photo, too weak to read as an edge; the rim draws the edge (6.4:1 or more against the glass) and the Rouge reads against the rim at 4.9:1. The words under the field stay the first signal. */
  --ui-field-glass-edge-invalid-rim: var(--ui-glass-fg); /* Round 8. The 1 px Porcelain rim outside the Rouge band of an invalid field on glass: the same Rouge cut with Porcelain as the alert disc beside the words. */
  --ui-field-glass-error: var(--ui-glass-fg); /* Round 8. The error message on glass is Porcelain, weight 500, never Rouge. Measured on the board: Rouge words on Smoke 1.3:1 over a white page and 1.6 to 3.2:1 over the photo; Porcelain words 6.4:1 over a white page and 8.0:1 or more over the photo. */
  --ui-field-glass-error-mark: var(--ui-danger); /* Round 8. The circle-alert before an error on glass: the same solid Rouge disc as on light ground, its exclamation cut through to Porcelain (--ui-field-glass-error-cut) instead of to the glass, so the mark reads 4.9:1 over any backdrop. */
  --ui-field-glass-error-cut: var(--ui-glass-fg); /* Round 8. What shows through the exclamation of the Rouge alert disc on glass: Porcelain. */
  --ui-otp-slot-width: 48px; /* One slot of a sign-in code at full size. Slots narrow evenly on a phone; the code stays one line. */
  --ui-otp-slot-height: 56px; /* Taller than a field: the code is the one thing on its screen. */
  --ui-otp-gap: var(--ui-space-sm); /* 8 px between slots in a group. */
  --ui-otp-separator: var(--ui-space-sm); /* The separator between groups of three is space, not a line: 8 more, so groups sit 24 apart, three times the gap inside a group. */
  --ui-otp-caret: var(--ui-text); /* The caret in the active empty slot: Ink. */
  --ui-kbd-height: 22px; /* A key: a soft sunken pill, 22 px, a circle for one character. */
  --ui-kbd-pad: 6px; /* 6 px at each end of a key, past half its radius, so a one-character key stays a circle and Esc a short pill. */
  --ui-kbd-bg: var(--ui-surface-sunken); /* Sunken, no stroke: the key is pressed into the surface, not drawn on it. */
  --ui-kbd-fg: var(--ui-text-secondary); /* Key labels, in the data face. */
  --ui-kbd-glass-bg: var(--ui-glass-button-clear); /* A key on glass (tooltips, menus, the command bar): the clear veil. */
  --ui-kbd-glass-fg: var(--ui-glass-fg-secondary); /* Key labels on glass. */
  --ui-dropzone-bg: var(--ui-surface-sunken); /* Round 8. The upload box: one step of sunken surface, a well pressed into the page. No dashed border and no stroke at all (rule few-strokes): the step is the edge. */
  --ui-dropzone-bg-hover: var(--ui-surface-sunken-hover); /* Hover with a mouse: one step toward Ink. */
  --ui-dropzone-bg-pressed: var(--ui-surface-sunken-hover); /* Pressed: stays on the hover step and shrinks (dropzone.press-scale), so a large surface never flashes dark. */
  --ui-dropzone-bg-drag: var(--fume-focus-100); /* Drag-over: the well keeps its resting Fog; the seat turning Ink is the sign, with the words that say where creatives go. No fill, no Amber and no shimmer here (round 11, Marcus 13 Oct: 'verken orange eller shimmer på where creatives land'); round 9 had Amber 50 (beige), round 8 Focus 300. */
  --ui-dropzone-fg: var(--ui-text); /* The line that says what to do: Ink, weight 500. */
  --ui-dropzone-meta: var(--ui-text-secondary); /* The limits line (JPG, PNG or MP4 · up to 200 MB) in the data face: secondary, not tertiary, so it keeps 7.3:1 on the hover step and 5.8:1 on the drag step. */
  --ui-dropzone-disc: var(--ui-ground); /* The round seat of the upload icon: Porcelain, lifted off the well with depth.raised. It is the one raised thing in the box. */
  --ui-dropzone-disc-drag: var(--ui-action-primary); /* The seat of the upload icon while creatives are over the box: Ink, the one dark thing in the box, so it reads as the place to aim (round 11; round 10's Amber seat was wrong here). */
  --ui-dropzone-disc-drag-fg: var(--ui-action-primary-fg); /* The upload icon on the Ink seat: Porcelain. */
  --ui-dropzone-disc-size: var(--ui-size-control-md); /* 40 px seat in the box. */
  --ui-dropzone-disc-size-compact: var(--ui-size-control-sm); /* 32 px seat in the one-row variant and in the Add more row. */
  --ui-dropzone-height: 176px; /* The empty box: tall enough to aim a drop at, short enough to sit above a form. Content centred, 24 inset all round. */
  --ui-dropzone-height-compact: 56px; /* The one-row variant (Reference images in a form) and the Add more row under added creatives: taller than a 40 px field so it reads as a place to drop, not a field to type in. */
  --ui-dropzone-press-scale: var(--ui-card-press-scale); /* A box is wide, so it shrinks like a card (0.985), half a button's 3 %. */
  --ui-dropzone-tile-min: 88px; /* Smallest thumbnail of an added creative: three across on a phone, also inside a dialog on a phone (310 px inside). In a wider box a tile is at least 14 % of it (dropzone.css), so a desktop box or a 640 px dialog shows six across. */
  --ui-dropzone-gap: var(--ui-space-xl); /* 24 px between the groups inside an upload: added creatives, rows still uploading, the Add more row. Rows inside a group sit 4 apart, tiles 24 down and 12 across with their caption 8 under them. */
  --ui-dropzone-glass-bg: var(--ui-glass-button-clear); /* The box on glass: the clear veil, no stroke. Porcelain text on it is 5.0:1 over the worst backdrop. */
  --ui-dropzone-glass-bg-hover: var(--ui-glass-button-clear-hover); /* Hover on glass: the veil lifts like a clear button. */
  --ui-dropzone-glass-bg-drag: rgb(27 20 16 / 0.24); /* Creatives dragged over the box on glass: the well deepens toward Ink instead of lighting up, so Porcelain text gains contrast while you aim. */
  --ui-dropzone-glass-disc: var(--ui-glass-button-clear); /* The icon's seat on glass, and the tile of a row's creative that has nothing to show yet: a clear veil, never white (the one white thing on a glass surface is its main button). */
  --ui-menubar-trigger: var(--ui-size-seg); /* A menu name in the bar (Campaign, Creative, View, Help): a 36 px quiet pill, 44 to touch. Open, it sits on the quiet hover surface in Ink. */
  --ui-menubar-gap: var(--ui-space-xs); /* Between the menu names (4 px): they read as one bar, without a container or a line under it. */
  --ui-menubar-content-width: 264px; /* Least width of a menubar menu (glass, radius float): room for an icon, the words and a shortcut in keys at the end. */
  --ui-menubar-sub-gap: var(--ui-space-sm); /* A submenu (Export as) opens 8 px beside its menu, so the two glasses read as two layers; its first row level with the row that opened it. */
  --ui-menubar-indicator: var(--ui-size-icon); /* The leading slot of a menubar row (16 px): the icon, or the check of a checkbox row, or the dot of a radio row, so every label in a menu starts on one line. */
  --ui-menubar-radio-dot: var(--ui-badge-dot); /* The dot of the chosen radio row (6 px, Porcelain on the glass). A checkbox row shows the check; neither is ever Amber. */
  --ui-toolbar-tray: var(--ui-surface); /* The tray the editor tools sit in: one step toward Ink on Porcelain, a pill with 6 px around the 40 px circles, so the tools read as one object without a stroke. */
  --ui-toolbar-group-gap: var(--ui-space-md); /* Between groups of tools (12 px), three times the 4 px inside a group: the separator is space, never a line. */
  --ui-toolbar-readout: 56px; /* The zoom readout (100 %) between zoom out and zoom in, in the data face; a fixed width, so the buttons never move when the number changes. */
  --ui-toolbar-bar-bottom: var(--ui-space-xl); /* The floating action bar sits 24 px above the bottom of the screen, plus the phone's safe area (env(safe-area-inset-bottom)). */
  --ui-toolbar-bar-margin: var(--ui-space-sm); /* Least room beside the floating action bar on a narrow screen (8 px, like the drawer), so the glass pill never touches the screen's edge. */
  --ui-toolbar-bar-z: 40; /* Stacking of the floating action bar and the settings save bar: over the page, under dialogs and drawers (50), so a confirm dialog's scrim covers the bar it came from. */
  --ui-resizable-gap: var(--ui-space-md); /* The handle between two panels is this space (12 px), not a line. Its hit area is 44 px wide all the same. */
  --ui-resizable-grip-thickness: 4px; /* The grip: a small pill in the middle of the gap, 4 px across. */
  --ui-resizable-grip-length: 32px; /* The grip's length at hover and focus. */
  --ui-resizable-grip-length-active: 48px; /* The grip's length while dragging: it stretches, so the hand feels it took hold. */
  --ui-resizable-grip-touch: var(--ui-surface-sunken-hover); /* The grip at rest where there is no hover (touch screens): always faintly there, one step above the layer behind. With a mouse it is hidden until hover or focus. */
  --ui-resizable-grip-hover: var(--ui-hairline-strong); /* The grip under the pointer or with keyboard focus (focus also draws the Ink ring around it). */
  --ui-resizable-grip-active: var(--ui-action-primary); /* The grip while dragging: Ink, the colour that decides. */
  --ui-resizable-step: 5; /* Percent a panel grows or shrinks per arrow key (Shift: twice that); Home and End go to the panel's least and most size. */
  --ui-stepper-marker: 24px; /* The step marker: a 24 px circle with the step number, the size of the selected creative's badge. */
  --ui-stepper-marker-gap: var(--ui-space-md); /* From the marker to its label (12 px); label to its description 4. */
  --ui-stepper-step-gap: var(--ui-space-xl); /* Between steps side by side (24 px, twice the 12 from a marker to its words). Steps are told apart by space and their numbers; there is no connector line. */
  --ui-stepper-row-gap: var(--ui-space-xl); /* Between steps stacked upright (24 px), twice the air inside a step. */
  --ui-stepper-marker-done: var(--ui-surface-sunken); /* A finished step: the Ink check on the sunken circle. Never Amber: Amber is only the Quality Gate check on a checked creative. */
  --ui-stepper-marker-upcoming: var(--ui-surface); /* A step still to come: its number in tertiary on the quietest circle, so the eye goes to the current step in Ink. */
  --ui-stepper-dot: var(--ui-badge-dot); /* The compact stepper on a phone (Step 2 of 5): one 6 px dot per step, Ink when done, sunken when still to come. */
  --ui-stepper-dot-current: 20px; /* The current step in the compact stepper: the dot stretched to a 20 px pill in Ink. */
  --ui-pagehead-crumb-gap: var(--ui-space-md); /* From the breadcrumb to the title (12 px). */
  --ui-pagehead-meta-gap: var(--ui-space-sm); /* From the title to its quiet meta line in the data face (8 px): they belong together. */
  --ui-pagehead-heading-min: 320px; /* The title keeps at least this much of its line before the actions wrap under it; below it they move to the next line instead of crushing the title. */
  --ui-pagehead-meta-separator: var(--ui-space-lg); /* The room each quiet dot takes between parts of the meta line (16 px, the dot centred). A dot that would start a line is clipped away. */
  --ui-pagehead-tabs-gap: var(--ui-space-xl); /* From the header to its tabs (24 px), three times the title-to-meta gap. */
  --ui-pagehead-actions-gap: var(--ui-space-sm); /* Between the header's actions (8 px). The primary action is the one Ink button, last in the row. */
  --ui-settings-page-max: 640px; /* The widest a settings page runs beside its navigation, so a form keeps a calm measure. */
  --ui-settings-gap: var(--ui-space-2xl); /* Between the settings navigation and its page (32 px). */
  --ui-settings-section-gap: var(--fume-space-7); /* Between sections of a settings page (48 px), twice the 24 px between fields: sections are parted by space, never a line. */
  --ui-settings-savebar-bottom: var(--ui-space-lg); /* The save bar floats 16 px above the bottom of the page (plus the safe area) once something has changed. */
  --ui-filterbar-search-min: 200px; /* The search's starting width in the row: chips and sort take their room first, then the search grows up to its full width; only when even this does not fit does the row wrap. */
  --ui-filterbar-search: 280px; /* The search field in a wide filter bar; on a phone it takes the whole row. */
  --ui-filterbar-sort: 200px; /* The sort select at the end of a wide filter bar (a field, radius 12, its listbox glass). On a phone sorting moves into the filter sheet. */
  --ui-filterbar-menu: 264px; /* Least width of a filter chip's glass menu: room for the option, its data hint and the check. */
  --ui-filterbar-gap: var(--ui-space-sm); /* Between the controls of the filter bar (8 px). */
  --ui-filterbar-row-gap: var(--ui-space-md); /* From the controls to the row of active filters and the result count (12 px). */
  --ui-filterbar-results-gap: var(--ui-space-xl); /* From the filter bar to the creatives it filters (24 px), twice the gap inside the bar. */
  --ui-filterbar-pill: var(--ui-size-control-sm); /* An active filter (Status: Waiting for Anna): a 32 px pill with its remove circle, 44 to touch. */
  --ui-filterbar-pill-bg: var(--ui-surface-sunken); /* An active filter pill: the sunken surface, the key in tertiary and the value in Ink. No stroke. */
  --ui-filterbar-pill-bg-hover: var(--ui-surface-sunken-hover); /* The remove circle in a filter pill under the pointer, and pressed. */
  --ui-filterbar-remove: 24px; /* The remove circle (x) at the end of a filter pill; its hit area is 44. */
  --ui-sidebar-width: 240px; /* The expanded app sidebar on the layer behind the page. */
  --ui-sidebar-width-icon: calc(var(--ui-size-hit) + 2 * var(--ui-space-md)); /* The collapsed icon rail: 44 px rounded squares (radius item) with 12 px of the layer behind on each side (68 px). Square, not round: Fume's rail (Marcus, 13 Oct). */
  --ui-sidebar-width-mobile: 288px; /* The sidebar as a glass drawer on a phone; never wider than the screen minus 56 px, so the page stays in view behind the scrim. */
  --ui-sidebar-row: var(--ui-size-control-md); /* A navigation row, 40 px; 44 on touch screens. The current row comes forward to Porcelain (--ui-behind-active) with --ui-depth-raised. */
  --ui-sidebar-gap: var(--ui-space-sm); /* The layer behind that shows around the page sheet (8 px). No stroke between the sidebar and the page: the sheet lies on the layer with --ui-depth-sheet. */
  --ui-sidebar-logo: 26px; /* Height of the Fume logo (the lockup) in the sidebar header: 103 px wide, above the 96 px minimum, the word as large as the old 18 px wordmark. Logo before mark before wordmark (F-D080). */
  --ui-sidebar-logo-mark: 24px; /* Height of the mark alone when the sidebar folds to the rail: the logo becomes its icon. */
  --ui-nav-height: calc(var(--ui-size-control-md) + 2 * var(--ui-space-md)); /* The site top bar: 40 px controls with 12 px of air above and below (64 px). */
  --ui-nav-link: var(--ui-size-seg); /* A link in the top bar: a 36 px quiet pill, 44 to touch. */
  --ui-nav-logo: 26px; /* Height of the Fume logo (the lockup) in the top bar: 103 px wide, above the 96 px minimum. Logo before mark before wordmark (F-D080). */
  --ui-nav-panel: 340px; /* Width of a top-bar dropdown: glass, radius float, rows with a title and one line of text. */
  --ui-breadcrumb-gap: var(--ui-space-xs); /* Between a crumb and its chevron separator (4 px); the chevron is the only divider, never a slash or a line. */
  --ui-pagination-size: var(--ui-size-control-md); /* A page button: a 40 px circle (two digits stay round), 44 to touch. The current page is Ink. */
  --ui-table-row-gap: var(--ui-space-xs); /* Space between rows (4 px). Rows are told apart by space and the hover surface, never by lines (few-strokes). */
  --ui-table-row-hover: var(--ui-surface); /* A row under the pointer: one step toward Ink on Porcelain. */
  --ui-table-row-selected: var(--ui-selected); /* A selected row: the faint Amber wash of color.selected, light on what you chose (round 10; round 9 had Amber 50, round 8 two steps toward Ink). The checkbox itself is Ink. */
  --ui-table-cell-x: var(--ui-space-md); /* Air sideways in a cell (12 px); the first and last cell keep --ui-inset-float (16) from the row's rounded ends. */
  --ui-table-cell-y: var(--ui-space-sm); /* Air above and below a cell (8 px). */
  --ui-table-head: var(--ui-size-control-sm); /* Header row height (32 px): label type in tertiary, sticky on scroll. */
  --ui-table-thumb: var(--ui-size-control-md); /* Width of the creative thumbnail in a row (40 px, 4:5, so 50 tall), with the creative's hairline edge. */
  --ui-calendar-day: var(--ui-size-control-md); /* A day: a 40 px circle. Selected is an Ink circle; on glass a Porcelain one. */
  --ui-calendar-cell: var(--ui-size-hit); /* A day's cell and hit area, 44 px. Narrow screens let the cells shrink and keep the 44 px hit area. */
  --ui-calendar-range: var(--ui-selected); /* The band between the two Ink ends of a range: the faint Amber wash of color.selected (round 10; round 9 had Amber 50, round 8 the sunken step); no outline. */
  --ui-calendar-range-on-glass: var(--ui-glass-button-clear-hover); /* The band of a range on glass: the clear veil, one step up. */
  --ui-calendar-today: 4px; /* Today: a small Ink dot under the date (Porcelain on a selected day). A dot, not a ring, so nothing draws a line. */
  --ui-tabs-gap: var(--ui-space-lg); /* Between the tab list and its panel (16 px). */
  --ui-tabs-vertical-width: 220px; /* The vertical tab list on a settings page: a sunken track with one white pill that slides, like the segmented control. */
  --ui-overlay-z-modal: 50; /* Stacking: dialogs, alert dialogs, sheets, drawers, the command palette and their scrims. */
  --ui-overlay-z-float: 60; /* Stacking: popovers, hover cards, context menus and listboxes, above a dialog they open from. */
  --ui-overlay-z-tooltip: 70; /* Stacking: tooltips, above everything they describe. */
  --ui-overlay-z-toast: 80; /* Stacking: toasts, the top layer, still readable while a dialog is open. */
  --ui-overlay-margin: var(--ui-space-lg); /* 16px. The least space between a floating layer and the edge of the screen: a dialog on a phone sits 16 in, a popover flips or shifts before it comes closer. */
  --ui-overlay-offset: var(--ui-space-sm); /* 8px. The gap between a trigger and the popover, hover card, menu, listbox or tooltip it opens. No arrow: the gap and the shadow say where it came from. */
  --ui-dialog-width-sm: 400px; /* Small dialog: confirmations and alert dialogs (Delete 3 creatives?). */
  --ui-dialog-width-md: 480px; /* Default dialog: a question with a short body (Send 12 creatives to the Quality Gate?). */
  --ui-dialog-width-lg: 640px; /* Large dialog: a decision that needs the work in view (the 12 creatives before they go to Anna). */
  --ui-sheet-width: 400px; /* A side sheet (creative details). On a phone the same content opens as a drawer from the bottom. */
  --ui-sheet-margin: var(--ui-space-md); /* 12px. The sheet floats this far from the top, side and bottom of the screen, so its 32 px corners show: a panel lying on the page, not a slab glued to the edge. */
  --ui-drawer-width: 480px; /* On a wide screen a drawer keeps a phone-like width, centred at the bottom. On a phone it spans the screen minus its margin. */
  --ui-drawer-margin: var(--ui-space-sm); /* 8px. The drawer floats this far from the sides and the bottom of a phone, so all four 32 px corners show. */
  --ui-drawer-top: var(--fume-space-7); /* 48px. Fully open, the drawer stops this far below the top of the screen: the page stays in view, so it reads as a layer that can go away. */
  --ui-drawer-snap: 0.6; /* The first snap point, as a share of the screen height. A drawer opens there and snaps to it, to fully open, or away when dragged below it. */
  --ui-drawer-handle-width: 40px; /* The grab handle is a short pill, not a line. */
  --ui-drawer-handle-height: 6px; /* Grab handle height: thick enough to read as a pill and to be found by a thumb. Its hit area is 44 x 44. */
  --ui-drawer-handle: rgb(255 253 249 / 0.42); /* Grab handle on glass: Porcelain at 42 %, quieter than text and clearer than the clear-button veil. */
  --ui-drawer-handle-active: rgb(255 253 249 / 0.7); /* Grab handle while dragged or pressed: it lifts toward Porcelain. */
  --ui-popover-width: 288px; /* A popover with a short task (Share with Anna: a note and one white button). */
  --ui-popover-hover-width: 288px; /* A hover card: the preview of a person or a creative. */
  --ui-popover-hover-delay: 500ms; /* A hover card waits this long before it opens, so a pointer passing over a name does not flash cards. */
  --ui-popover-hover-close-delay: 240ms; /* A hover card stays this long after the pointer leaves, so the pointer can travel into it. */
  --ui-tooltip-delay: 500ms; /* A tooltip waits this long under a resting pointer. Keyboard focus shows it at once. */
  --ui-tooltip-skip-delay: 300ms; /* Moving from one trigger to the next within this time shows the next tooltip at once, as in a toolbar. */
  --ui-tooltip-long-press: 500ms; /* On a touch screen a press this long shows the tooltip (and a context menu). A tap acts as usual. */
  --ui-toast-width: 400px; /* Every toast is the same pill, so a stack lines up and the depth reads cleanly. On a phone: the screen minus 16 each side. */
  --ui-toast-bottom: var(--ui-space-xl); /* 24px. Toasts sit this far above the bottom of the screen (plus the safe area), centred. */
  --ui-toast-peek: var(--ui-space-sm); /* 8px. How far each older toast shows above the one in front of it in a stack of up to three. */
  --ui-toast-depth-scale: 0.05; /* Each older toast in the stack is 5 % smaller: depth without a line or a second shadow colour. */
  --ui-toast-duration: 5000ms; /* A toast leaves on its own after this time; the timer pauses while the pointer or focus is on the stack. */
  --ui-toast-duration-long: 8000ms; /* Errors and toasts with an action (Undo) stay longer, so the action can be reached. */
  --ui-toast-swipe: var(--fume-space-7); /* 48px. A swipe this far (sideways or down) dismisses a toast; shorter, it springs back. */
  --ui-command-width: 560px; /* The command palette (⌘K). On a phone: the screen minus 16 each side. */
  --ui-command-list-height: 360px; /* The results scroll inside this height; the search field and the key hints stay put. */
  --ui-command-top: 12vh; /* The palette opens high on the screen, not centred, so the list can grow downward without the field jumping. */
  --ui-qg-panel-width: 360px; /* Anna's side panel on a wide screen: the Brand DNA checklist, her notes and the decision. Under 720 px of screen it becomes a glass sheet at the bottom. */
  --ui-qg-well: var(--ui-surface-sunken); /* The well the creative sits in: one step below the page, so the white creative and its hairline come forward. The work is the brightest thing on the screen. */
  --ui-qg-media-feed: 400px; /* Widest a Feed creative (4:5) shows in the well; a Story (9:16) shows narrower and a Banner (1.91:1) wider, so all three read at about the same weight. */
  --ui-qg-media-story: 288px; /* Widest a Story creative (9:16) shows in the well. */
  --ui-qg-media-banner: 640px; /* Widest a Banner creative (1.91:1) shows in the well. */
  --ui-qg-pin: 28px; /* Anna's numbered pin on the creative: a 28 px drop whose point (the square corner) sits on the spot. Its hit area is 44. */
  --ui-qg-pin-bg: var(--ui-glass-button-white); /* A pin at rest: Porcelain at 94 %, the white of the main glass button, with an Ink number and the small glass shadow, so it reads on any photo without a ring. */
  --ui-qg-pin-active: var(--ui-action-primary); /* The pin whose note is open, hovered or focused: Ink with a Paper number. Ink decides; never Amber, which is only the check. */
  --ui-qg-marker: 20px; /* The checklist's marks: the Ink check on an item that passed, and the small pin (the same drop as on the creative) on an item with a note. */
  --ui-qg-note-bg: var(--ui-surface); /* A checklist item with a note, and Anna's comment: one surface step off the page. Changes are told in words, never in red. */
  --ui-qg-key-on-ink: rgb(255 253 249 / 0.16); /* The shortcut key inside the Ink Approve button (A): a Porcelain veil, like a clear glass button, so the key reads without a stroke. */
  --ui-qg-key-on-ink-fg: rgb(255 253 249 / 0.86); /* The letter on that key: Porcelain at 86 %, 13:1 on Ink. */
  --ui-qg-seal-height: var(--ui-size-control-sm); /* The status seal on the creative (In check, Checked, Changes requested): a white 32 px pill lifted by depth, in the creative's bottom-left corner. */
  --ui-qg-land-scale: 1.8; /* The check moment: the checked triangle lands from 1.8 times its size and from blur to sharp (soft to sharp), over --ui-motion-slow. Calm, once, no bounce. */
  --ui-qg-land-blur: 6px; /* How soft the checked triangle starts before it lands sharp. */
  --ui-qg-peek: 188px; /* On a phone the sheet first shows only the summary and the decision: this much of the screen's foot is kept clear for it, so the creative above stays whole. */
  --ui-qg-phone-height: 720px; /* Height of the review screen in its phone layout on the board (the app uses the whole screen). */
  --ui-viewer-ground: var(--fume-focus-900); /* The viewer's ground: Ink. Allowed here only, because a creative is judged best on dark, with nothing else in view. */
  --ui-viewer-fg: var(--fume-porcelain); /* Text and icons on the Ink ground, 17.9:1. */
  --ui-viewer-fg-secondary: rgb(255 253 249 / 0.72); /* Secondary text on Ink and on the info panel: Porcelain at 72 %, 9:1 or better. */
  --ui-viewer-surface: var(--fume-focus-800); /* The info panel on the Ink ground: one step lighter, no stroke. Glass would vanish on Ink, so the panel steps up instead of blurring. */
  --ui-viewer-tool-on: rgb(255 253 249 / 0.2); /* A tool on the Ink ground that is on (the info panel shown): the clear veil (Porcelain at 10 %, the glass-clear button) doubled. The tools themselves are .ui-btn--glass-clear: on Ink the veil reads as it does on Smoke. */
  --ui-viewer-panel-width: 320px; /* The info panel beside the creative on a wide screen; on a phone it rises from the bottom. */
  --ui-viewer-pad: var(--ui-space-2xl); /* Least air between the creative and the edge of the viewer's stage (32), so the creative never touches the tools. */
  --ui-viewer-zoom-max: 3; /* Zoom steps: fit, 1.5, 2 and 3 times. Past fit the creative pans with a drag. */
  --ui-viewer-swipe: var(--fume-space-7); /* 48px. A swipe this far sideways moves to the next or previous creative; shorter, the creative springs back. */
  --ui-notify-width: 380px; /* The bell's popover: a glass float wide enough for two lines of a notification beside its avatar. */
  --ui-notify-row: 68px; /* One notification in the popover: every row the same height (two lines of text), so the list can stop on half a row. */
  --ui-notify-label: var(--ui-size-control-sm); /* A group label (Today, Yesterday) in the popover list. */
  --ui-notify-rows-visible: 3.5; /* The popover list stops after three and a half rows: the half row says there is more below (never a sliver). */
  --ui-notify-dot: var(--ui-badge-dot); /* Unread: a 6 px dot in front of the row, Ink on the page and Porcelain on glass, with the words at full strength. Never blue, never Amber. */
  --ui-notify-dot-on-page: var(--ui-text); /* The unread dot on the page: Ink. */
  --ui-notify-dot-on-glass: var(--ui-glass-fg); /* The unread dot on glass: Porcelain. */
  --ui-notify-count: 18px; /* The unread count on the bell: an 18 px Ink pill with Paper numbers, cut out of the bar with the ground colour. */
  --ui-notify-inbox-width: 760px; /* The inbox page's column: a calm reading width, centred on a wide screen. */
  --ui-notify-thumb: var(--ui-size-control-sm); /* A creative thumbnail in an inbox row (32 wide, 4:5), with the creative's hairline. */
  --ui-share-width: 560px; /* The share dialog: wide enough for the email, the role and Invite on one line, and a person's name and role side by side. On a phone it is a sheet at the bottom. */
  --ui-share-role-width: 152px; /* The role select beside the email field (Viewer, Can comment, Can approve). */
  --ui-share-copied: 2000ms; /* How long Copy link says Copied before it turns back. */
  --ui-share-list-max: 236px; /* People with access scroll inside this height: four rows and half of the fifth. */
  --ui-onboard-measure: 52ch; /* Line length of the welcome text. */
  --ui-onboard-step-min: 232px; /* Narrowest step card: three side by side on a wide screen, one under the other on a phone. */
  --ui-onboard-mark: 28px; /* The step's mark: its number on the sunken step, and an Ink circle with a Paper check once it is done. Never Amber: Amber is only a creative Anna checked. */
  --ui-onboard-ground: var(--ui-ground-warm); /* The first run lies on Paper: a brand moment, the welcome, edge to edge like a Paper section (decided with Warmer, Marcus 13 Oct; round 9; round 8 had Porcelain). */
  --ui-onboard-card: var(--ui-ground); /* On Paper the step cards and the empty campaigns are Porcelain, so a card never matches its ground. */
  --ui-web-ground-brand: var(--fume-brown); /* A dark brand section: Brown, with Paper text. Website, decks and social only; never a card, a button or product UI, where Ink makes every decision (RULES Colour, F-D079). Never two in a row. */
  --ui-web-text-on-brand: var(--fume-paper); /* Text and the logo on a Brown section, 12.2:1. Never Ink on Brown (1.4:1). */
  --ui-web-text-on-brand-secondary: var(--fume-sand); /* Quieter text on Brown (a label over a title), 9.1:1. */
  --ui-web-frame: var(--fume-paper); /* The Focus frame's corners and point on a photograph, on a light image or a dark one (F-D082). On a flat ground the frame is Paper on Ink or Brown and Ink on Paper or Porcelain. Amber only where the check lands (--ui-check). */
  --ui-web-title-on-warm: var(--fume-brown); /* A marketing title on a Paper section: Brown, 12.2:1, as on the deck's cover, dividers and contact slide. Running text on Paper stays Ink. */
  --ui-web-point: var(--fume-amber); /* The Amber point that ends a statement on Brown (deck D5; Amber point on dark, F-O020). A point, never text, a surface or light on Brown. One per page. */
  --ui-web-light-ground: var(--fume-paper); /* The ground the brand light sits on (Light board L1, L2, L5). Light only on Paper or Cream, never on Ink or Brown, never behind small text. */
  --ui-web-light-ground-cream: var(--fume-cream); /* The ground for light L3. */
  --ui-web-light-soft: var(--fume-amber-100); /* The light's soft wash (L1, L5): Amber 100, blurred wide, so it reads as light, never as a colour block. */
  --ui-web-light-warm: var(--fume-amber-200); /* The light's warm body (L2, L3). */
  --ui-web-light-core: var(--fume-amber); /* The light's core (L2, L3, L5), blurred so far it is light, not a shape. Never a fill anyone could read as an Amber surface. */
  --ui-web-page: 1120px; /* Widest the page's content gets, the same as the brand book. */
  --ui-web-measure: 60ch; /* Running text and ledes never run wider than this. */
  --ui-web-gutter: var(--ui-space-xl); /* Space between the content and the window's edge: 24 px, 16 on a phone (gutter-phone). */
  --ui-web-gutter-phone: var(--ui-space-lg); /* The gutter under 760 px: 16 px. */
  --ui-web-section: var(--fume-space-10); /* Space above and below the content of a section: 96 px, 64 on a phone (section-phone). Sections are told apart by their ground and this space, never by lines. */
  --ui-web-section-phone: var(--fume-space-8); /* The section space under 760 px: 64 px. */
  --ui-web-title-gap: var(--ui-space-xl); /* Between a title and the lede or text under it: 24 px. The next group sits at least twice as far away (rule proximity). */
  --ui-web-group-gap: var(--fume-space-7); /* Between groups in a section (a lede and its buttons, a title and its cards): 48 px. */
  --ui-web-header: var(--ui-size-control-lg); /* Height of the page header's row: the logo on the left, one action on the right. */
  --ui-web-logo: 120px; /* Width of the horizontal logo lockup in the page header (the official file, never redrawn). */
}
