{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "theme",
  "type": "registry:item",
  "title": "Quartz theme",
  "description": "Support file: tokens, scoped base styles and the Tailwind v4 theme mapping.",
  "author": "design.how",
  "categories": [
    "internal"
  ],
  "dependencies": [
    "tailwindcss@^4.3.3",
    "@tailwindcss/postcss@^4.3.3"
  ],
  "registryDependencies": [
    "https://design.how/r/quartz/skill.json",
    "https://design.how/r/quartz/portal.json"
  ],
  "docs": "Quartz is scoped: its styles apply only inside an element with the class quartz.\n1. Import the theme once, in the root layout, as its own stylesheet (not an @import in globals.css): import '@/components/quartz/styles.css'\n2. Put className=\"quartz\" on the element that holds Quartz UI, usually <body>. Quartz's classes work on the elements inside it, in your own code too, not on that element itself.\n3. Wrap the app inside that element in <QuartzPortalProvider> from '@/lib/quartz/portal', so dialogs and menus keep the theme.\nDark mode: put data-theme=\"dark\" or the class dark on the quartz element or any ancestor, such as <html>. The theme does not follow the system setting (prefers-color-scheme) on its own.\nComponents: npx shadcn@latest add https://design.how/r/quartz/<name>.json; https://design.how/r/quartz/registry.json lists them all.",
  "meta": {
    "docs": "https://design.how/systems/quartz.md",
    "page": "https://design.how/systems/quartz"
  },
  "files": [
    {
      "path": "registry/quartz/tokens.css",
      "content": "/* Quartz tokens. The one file to retune.\n\n   Palette: Frost. Cold navy ink on icy paper, cards on a cool fog canvas, and five cold kind tints. A kind shows as a word, never a fill.\n\n   Rules\n   - Hue names a kind of thing. Ink carries all text. Hue never colors text.\n   - Five kind slots, in this order: agent cyan (h195), key orchid (h320), run blue (h250), deploy violet (h290)\n     and model mint (h160). Two reserved status hues: warn amber (h68) and fail red (h26).\n   - Warm means warn or fail. Every warm hue on screen (red, orange, amber, yellow, h0 to h90) is trouble.\n     No kind, chart series, decoration or brand accent may take a warm hue, and the chassis has none.\n   - Components never name a hue. They read --accent-mark, --accent-field, --accent-wash and\n     --accent-line, which [data-kind] or [data-status] set on the nearest element.\n   - Every hue has six steps. mark: bar fills, chart fills, legend squares. field: the flat full-bleed\n     or inset field behind a section or product UI. wash: selection and focus in the app. line: a darker\n     step for chart lines, outlines and other 1-2px marks that must meet 3:1 (WCAG 1.4.11). tint and label:\n     the kind label, a soft ground and the dark word set on it.\n   - Text on a hue uses --accent-on-field on a field and --text-on-field on a mark, fixed dark in both\n     themes. Text on a wash is ink, because the wash flips with the theme. The kind label is the one\n     tinted text: --accent-label on --accent-tint.\n   - Floors, worked out on Quartz's color page (design.how/systems/quartz/foundations/color): ink on every field and wash is at\n     least 7.5:1, ink on every mark at least 5:1, every line step at least 3:1 on paper and on the grey\n     card, and every label at least 4.5:1 on its tint, in both themes. The dark theme points each line at\n     its mark. Fills are flat: no ring, no shadow.\n   - Everything is OKLCH and inside sRGB. Each component has one quiet grey frame line (--line-frame) with row rules inside it. The grey\n     field is a well for code and output, never a container. Nothing casts a shadow except overlays.\n\n   Format\n   - One declaration per line: --name: value; followed by a comment of the form job | used by.\n   - A line that starts with == opens a token group. Tools that list Quartz's tokens read both, so keep\n     them when you retune.\n\n   Scope: the tokens live on .quartz, not :root, so an app's own --space-* and --font-* on :root stay\n   as they are. Derived tokens are declared again on [data-surface] so an inverse section\n   recomputes them from its own ink and paper channels. */\n\n/* Fonts. Quartz is drawn in Quartz Sans (Normal width) and Quartz Mono, which are declared\n   on Quartz's own pages only and are not part of this theme. This file declares no @font-face, so each family\n   stack (--font-sans, --font-mono) renders its fallback: the platform's UI sans and monospace.\n   With a licence of your own, declare @font-face rules named \"Quartz Sans\"\n   and \"Quartz Mono\", and they take over. */\n\n.quartz {\n  /* == Ink and paper == */\n  --ink-c: 20% 0.024 262; /* the ink channel: cold navy graphite, 18.0:1 on --surface-page and 15.9:1 on --surface-card; every text and line is this at an alpha | all ink tokens */\n  --paper-c: 99.7% 0.001 250; /* the paper channel: an icy white | all paper tokens */\n  --grey-c: 95.6% 0.004 255; /* the grey field channel, cool like the ink | surface-card */\n  --canvas-c: 99.1% 0.002 250; /* the canvas channel: the cool fog behind cards and frames | surface-canvas */\n  --text-on-field-c: 20% 0.024 262; /* the fixed dark channel: text on hue and every shadow; never flips | text-on-field, elev-overlay */\n  --shadow-alpha: 0.20; /* overlay shadow strength; the dark theme raises it | elev-overlay */\n\n  /* == Category hues == */\n  --hue-1-mark: oklch(86% 0.120 195); /* agent cyan mark, 12.4:1 with --text-on-field | bar fill, chart fill, legend square */\n  --hue-1-field: oklch(92% 0.090 195); /* agent cyan field, 14.8:1 with --text-on-field | full-bleed section, product-line area */\n  --hue-1-wash: oklch(96.5% 0.040 195); /* agent cyan wash, 16.6:1 with --text-1 | selected row, focused panel */\n  --hue-1-line: oklch(60% 0.100 195); /* agent cyan line, 3.7:1 on --surface-page, 3.3:1 on --surface-card | chart line, outline */\n  --hue-1-tint: oklch(89% 0.050 195); /* agent cyan label ground, 13.3:1 with --text-on-field | kind label */\n  --hue-1-label: oklch(38% 0.062 195); /* agent cyan label word, 7.1:1 on --hue-1-tint | kind label */\n  --hue-2-mark: oklch(82% 0.080 320); /* key orchid mark, 10.1:1 with --text-on-field | bar fill, chart fill, legend square */\n  --hue-2-field: oklch(90% 0.060 320); /* key orchid field, 13.2:1 with --text-on-field | full-bleed section, product-line area */\n  --hue-2-wash: oklch(96% 0.030 320); /* key orchid wash, 16.0:1 with --text-1 | selected row, focused panel */\n  --hue-2-line: oklch(58% 0.075 320); /* key orchid line, 4.4:1 on --surface-page, 3.9:1 on --surface-card | chart line, outline */\n  --hue-2-tint: oklch(89% 0.050 320); /* key orchid label ground, 12.8:1 with --text-on-field | kind label */\n  --hue-2-label: oklch(38% 0.062 320); /* key orchid label word, 7.3:1 on --hue-2-tint | kind label */\n  --hue-3-mark: oklch(72% 0.100 250); /* run blue mark, 7.3:1 with --text-on-field | bar fill, chart fill, legend square */\n  --hue-3-field: oklch(82% 0.060 250); /* run blue field, 10.4:1 with --text-on-field | full-bleed section, product-line area */\n  --hue-3-wash: oklch(94.5% 0.020 250); /* run blue wash, 15.4:1 with --text-1 | selected row, focused panel */\n  --hue-3-line: oklch(52% 0.150 250); /* run blue line, 5.5:1 on --surface-page, 4.8:1 on --surface-card | chart line, outline */\n  --hue-3-tint: oklch(89% 0.050 250); /* run blue label ground, 13.1:1 with --text-on-field | kind label */\n  --hue-3-label: oklch(38% 0.062 250); /* run blue label word, 7.2:1 on --hue-3-tint | kind label */\n  --hue-4-mark: oklch(72% 0.110 290); /* deploy violet mark, 7.1:1 with --text-on-field | bar fill, chart fill, legend square */\n  --hue-4-field: oklch(83% 0.065 290); /* deploy violet field, 10.6:1 with --text-on-field | full-bleed section, product-line area */\n  --hue-4-wash: oklch(95% 0.025 290); /* deploy violet wash, 15.6:1 with --text-1 | selected row, focused panel */\n  --hue-4-line: oklch(54% 0.150 290); /* deploy violet line, 5.3:1 on --surface-page, 4.7:1 on --surface-card | chart line, outline */\n  --hue-4-tint: oklch(89% 0.050 290); /* deploy violet label ground, 12.9:1 with --text-on-field | kind label */\n  --hue-4-label: oklch(38% 0.062 290); /* deploy violet label word, 7.3:1 on --hue-4-tint | kind label */\n  --hue-5-mark: oklch(75% 0.100 160); /* model mark, 8.5:1 with --text-on-field | bar fill, chart fill, legend square */\n  --hue-5-field: oklch(90% 0.070 160); /* model field, 13.8:1 with --text-on-field | full-bleed section, product-line area */\n  --hue-5-wash: oklch(96% 0.035 160); /* model wash, 16.3:1 with --text-1 | selected row, focused panel */\n  --hue-5-line: oklch(52% 0.090 160); /* model line, 5.2:1 on --surface-page, 4.6:1 on --surface-card | chart line, outline */\n  --hue-5-tint: oklch(89% 0.050 160); /* model label ground, 13.3:1 with --text-on-field | kind label */\n  --hue-5-label: oklch(38% 0.062 160); /* model label word, 7.1:1 on --hue-5-tint | kind label */\n\n  /* == Reserved status hues == */\n  --warn-mark: oklch(80% 0.152 68); /* amber: degraded, slow, retrying; 9.4:1 with --text-on-field; warm, so never a kind | warn chip */\n  --warn-field: oklch(89% 0.056 68); /* warn field, 12.9:1 with --text-on-field | warn banner, warn toast */\n  --warn-wash: oklch(96% 0.028 68); /* warn wash, 16.1:1 with --text-1 | warn row */\n  --warn-line: oklch(62% 0.132 68); /* warn line, 3.7:1 on --surface-page, 3.3:1 on --surface-card | warn series, warn outline */\n  --fail-mark: oklch(65.2% 0.219 26); /* red: errored, crashed, 5xx; 5.1:1 with --text-on-field; warm, so never a kind | destructive button */\n  --fail-field: oklch(82% 0.055 26); /* fail field, 10.2:1 with --text-on-field | fail banner, fail toast */\n  --fail-wash: oklch(94.5% 0.027 26); /* fail wash, 15.3:1 with --text-1 | fail row, invalid field */\n  --fail-line: oklch(60% 0.236 26); /* fail line, 4.4:1 on --surface-page, 3.9:1 on --surface-card | fail series, fail outline */\n  --warn-text: oklch(49% 0.100 68); /* warn word, 6.4:1 on --surface-page, 5.6:1 on --surface-card | status word, warn text */\n  --fail-text: oklch(51% 0.180 26); /* fail word, 6.3:1 on --surface-page, 5.6:1 on --surface-card | status word, error text */\n\n  /* == Type families == */\n  --font-sans: \"Quartz Sans\", ui-sans-serif, system-ui, sans-serif; /* all UI and prose: Quartz Sans where declared, else the platform UI sans | every text role */\n  --font-mono: \"Quartz Mono\", ui-monospace, \"SF Mono\", Menlo, monospace; /* Quartz Mono where declared, else the platform monospace | ordinals, codes, IDs, code blocks */\n\n  /* == Type weights == */\n  --weight-body: 340; /* Regular | running text */\n  --weight-medium: 400; /* Medium | labels, buttons, headings, display */\n  --weight-strong: 500; /* Semibold | emphasis inside prose, code keywords */\n  --width-normal: normal; /* each face's own width; Quartz Sans's Normal file has no width axis, and a \"wdth\" value here would stretch the fallback sans | every role */\n  --features-data: \"tnum\", \"zero\", \"ss04\"; /* tabular figures, slashed zero, serif I; every duration, count and value | tables, labels, stats, data roles */\n  --features-id: \"ss04\"; /* serif I tells I, l and 1 apart | identifiers in sans */\n\n  /* == Type roles == */\n  --type-display-xl: 400 80px/80px var(--font-sans); /* marketing hero, line-height 1.0 | hero */\n  --type-display-lg: 400 60px/66px var(--font-sans); /* section heads, line-height 1.1 | marketing sections */\n  --type-display: 400 40px/44px var(--font-sans); /* mobile hero, page titles with stats | app page title, docs H1 */\n  --type-heading-lg: 400 32px/36px var(--font-sans); /* page titles | docs H1 on mobile, settings title */\n  --type-heading: 400 24px/28px var(--font-sans); /* panel and section titles | docs H2, dialog title */\n  --type-heading-sm: 400 20px/24px var(--font-sans); /* subsection titles | docs H3, card title */\n  --type-heading-xs: 400 16px/20px var(--font-sans); /* in-thread headings | response ## */\n  --type-body-lg: 340 16px/22px var(--font-sans); /* marketing and docs prose, line-height 1.4 | docs lede */\n  --type-body: 340 14px/20px var(--font-sans); /* app prose | descriptions, table text */\n  --type-body-sm: 380 13px/18px var(--font-sans); /* dense meta, a step heavier than body so meta on text-3 still reads | captions, helper text */\n  --type-button: 400 16px/20px var(--font-sans); /* default and large button label | button */\n  --type-label: 400 14px/16px var(--font-sans); /* controls and table cells | input, menu item, tab */\n  --type-label-sm: 400 12px/16px var(--font-sans); /* small tags, column heads | badge, table head */\n  --type-code: 400 13px/20px var(--font-mono); /* code blocks | code block, log line */\n  --type-code-sm: 400 12px/16px var(--font-mono); /* IDs, ordinals, paths in tables | inline code, kbd */\n  --type-tag: var(--type-code-sm); /* ids, methods, status codes and paths in a row or a code tag; the metrics of code-sm under its own name so the two cannot drift | row id, code tag, key tail */\n  --type-code-display: 400 32px/36px var(--font-mono); /* a code a person reads aloud or types on another device | CLI device code, recovery code */\n  --type-code-touch: 400 16px/22px var(--font-mono); /* code typed into a field on touch; 16px so iOS WebKit does not zoom on focus (trap/touch-input-zoom) | terminal input, code inputs below 640px */\n  --type-stat-xl: 400 48px/52px var(--font-sans); /* marketing stat numerals, tabular figures, plain sans | stat size xl */\n  --type-stat-lg: 400 40px/44px var(--font-sans); /* hero stat in the app, tabular figures | stat size lg */\n  --type-stat: 400 32px/36px var(--font-sans); /* app stat numerals, tabular figures | stat, metric */\n  --type-state-word: 400 14px/16px var(--font-sans); /* status words, the label role in sentence case | status word */\n  --tracking-display: -0.025em; /* display sizes | display-xl, display-lg, display */\n  --tracking-heading: -0.015em; /* heading sizes | heading-lg, heading, heading-sm */\n  --tracking-body: -0.01em; /* 16px text: body-lg and button | body-lg, button */\n  --tracking-text: 0em; /* 14px and below, where negative tracking closes the counters | body, body-sm, label, label-sm */\n\n  /* == Space == */\n  --space-0-5: 2px; /* optical nudge | tag inner gap */\n  --space-1: 4px; /* icon to label inside tags | tag, badge */\n  --space-2: 8px; /* control inner gap, button arrow gap | button, input */\n  --space-3: 12px; /* control padding, table cell padding | input, table */\n  --space-4: 16px; /* card padding, mobile gutter, button padding | card, button */\n  --space-5: 20px; /* grid gap in the app | grid */\n  --space-6: 24px; /* section padding in the app, desktop gutter | panel, docs */\n  --space-8: 32px; /* between app sections | docs sections */\n  --space-10: 40px; /* marketing block gap | marketing */\n  --space-15: 60px; /* marketing sub-section gap | marketing */\n  --space-20: 80px; /* marketing section gap | marketing */\n  --space-30: 120px; /* hero top padding | hero */\n\n  /* == Layout == */\n  --container: 1120px; /* marketing and docs content width | page container */\n  --sidebar: 248px; /* app and docs sidebar width | sidebar */\n  --toc: 200px; /* docs on-this-page column | docs layout */\n  --topbar: 56px; /* app and docs top bar height | top bar */\n  --gutter: 24px; /* page gutter at desktop | page */\n  --gutter-sm: 16px; /* page gutter on phones | page */\n  --control-xs: 24px; /* the action in a 40px header, 8px from its edges | button xs, chip xs, segmented xs, filter bar xs */\n  --control-sm: 28px; /* small control height, the sm of every control | button sm, chip, segmented sm, field sm, tag input */\n  --control: 32px; /* default control height, wider than tall: 16px of padding a side | button, input, select, slider thumb */\n  --tag: 20px; /* a tag's height: the smallest box that holds a 12px label, a count or a key cap | badge, code tag, kbd, ink slot sm, sidebar count */\n  --control-lg: 44px; /* large control and touch target | button lg */\n  --overlay-sm: 400px; /* small dialog and confirm width | dialog sm, alert dialog */\n  --overlay: 480px; /* default dialog, sheet and drawer content width | dialog, sheet, drawer */\n  --overlay-lg: 640px; /* wide dialog for forms and previews | dialog lg */\n  --popover: 288px; /* popover and picker panel width | popover, mode picker */\n  --toast-width: 384px; /* toast stack width from 640px up; full width below | toaster */\n  --popover-sm: 256px; /* a short info panel opened from an info button | popover info */\n  --tooltip-max: 256px; /* tooltip line length before it wraps | tooltip, chart tooltip */\n  --hint-width: 420px; /* widest a full-text hint grows; still capped at the viewport less the phone gutters | truncate hint */\n  --menu-min: 192px; /* narrowest a menu opens, so short labels still give a usable target row | dropdown menu, filter bar menu, attachment row */\n  --popup-max: 320px; /* tallest a list popup grows before it scrolls | select, combobox, command list, prompt-input menu, chart data table */\n  --menu-width: 320px; /* width the @ and / list opens at beside the caret; narrower on a phone | prompt-input menu */\n  --field-max-height: calc(var(--control-lg) * 4); /* tallest a wrapping chips field grows, four touch rows, before it scrolls | combobox chips */\n  --row-sm: 32px; /* compact row, for dense data | table size sm */\n  --row: 40px; /* default row, one line | table, item */\n  --row-lg: 56px; /* a row with a second line | table size lg, item with a description */\n  --label-column: 160px; /* widest a description-list label column grows before it wraps | data list */\n  --measure: 68ch; /* long-form reading measure | prose */\n  --tab-max: 220px; /* widest a document tab grows before its title truncates | tabs document variant */\n  --sidebar-icon: calc(var(--control) + var(--space-4)); /* collapsed sidebar width: one control plus 8px a side | sidebar icon mode */\n  --attachment-media: 40px; /* the media square in an attachment row; size sm uses 32px, --row-sm | attachment */\n  --attachment-max: 256px; /* widest an attachment chip in the composer grows before its name truncates | prompt-input attachment */\n  --grab-size: 40px; /* length of a sheet's grab bar | sheet */\n  --fade-edge: 24px; /* the mask fade at the clipped edge of a sideways scroller | suggestions scroll */\n  --fade-line-end: 16px; /* the mask fade at the end of one line of text that overflows, in place of an ellipsis | segmented control label */\n  --measure-hint: 60ch; /* a description under a title, a page lede or a field's hint, shorter than prose | field description, section description, page header description */\n  --measure-short: 48ch; /* an empty state's title and line, set top-left in the body | empty state */\n  --page-header-max: 720px; /* widest a page header's title block grows beside its actions | page header */\n  --search-min: 200px; /* narrowest the filter bar's search gets before the filters wrap under it | filter bar */\n  --search-max: 320px; /* widest the filter bar's search grows once the bar has room | filter bar */\n  --crumb-floor: 8ch; /* shortest the page crumb truncates to before the trail folds another crumb | breadcrumb trail */\n  --log-level: 5ch; /* the level column, as wide as the longest level word | log viewer */\n  --status-column: 128px; /* a right-aligned status column, wide enough for the status \"Waiting on you\" | table, tool call, timeline */\n  --timeline-name: 200px; /* the widest the name column of a timeline gets from 576px; narrower frames give it 40%, and never less than --timeline-name-min | timeline */\n  --timeline-name-min: 120px; /* the least the name column of a timeline keeps, so a label never shrinks to a stub | timeline */\n  --timeline-label-min: 10ch; /* the least a span name keeps before its figure is hidden, so a name never shrinks to a stub | timeline */\n  --time-column: 12ch; /* a column of relative times, wide enough for the first paint's date (\"Sep 30, 2025\") so the swap to \"3m ago\" never moves it | relative time column */\n  --stat-placeholder: 4ch; /* the loading bar standing in for a stat's value, about four digits | stat */\n  --tool-detail-min: 6ch; /* the least of a tool call's detail kept before its status wraps to a second line | tool call */\n  --line-box: 1lh; /* one line of the text it sits in; lh resolves where it is read | prose rhythm, stat, status, toast mark, date picker field, prompt input, tool call output */\n  --skeleton-text: 0.7em; /* a text skeleton bar, about the cap height of the text it stands for | skeleton text */\n  --code-inline: 0.9em; /* inline code, a step under the text around it so mono does not look larger | code */\n\n  /* == Radius == */\n  --radius-0: 0px; /* a straight edge: the shared edges of cells in a strip, bitmap pixels | frame-shared inner edges, switch thumb */\n  --radius-inner: 4px; /* a box inside a control or a row: the selected segment, badges, chips, row fills, a menu item | segment thumb, badge, chip, menu item */\n  --radius-soft: 6px; /* a control: buttons, fields, the segmented track, code tags | button, input, select, segmented control */\n  --radius-frame: 10px; /* a component's outer edge and every overlay | card, table, dialog, popover, menu, toast */\n  --radius-full: 999px; /* round means a person: avatars and the presence mark, plus the radio so it never reads as a checkbox | avatar, presence, radio */\n\n  /* == Lines == */\n  --line-hair: 1px; /* dividers, rings | separator, ring */\n  --line-accent: 2px; /* the 2px accent stroke | active tab underline, progress connector, table resize handle, chart line */\n  --line-focus: 2px; /* focus outline width | every focusable */\n  --focus-offset: 2px; /* focus outline offset | every focusable */\n  --line-frame-alpha: 0.14; /* the ink alpha of a frame's edge: a quiet grey line, so a screen of frames reads light | line-frame */\n  --mark-size: 8px; /* the legend square and the menu radio dot | chart legend, radio item */\n  --ring-cutout: 2px; /* the gap ring that cuts an overlapping avatar out of the surface | avatar group */\n  --chart-dash: 6 4; /* stroke-dasharray for a comparison or projected series | chart */\n  --chart-axis-gap: 8px; /* gap between a tick label and the plot; chart.tsx reads it into its layout | chart */\n\n  /* == Motion == */\n  --dur-press: 60ms; /* press feedback | button */\n  --dur-fast: 120ms; /* hover: color, wash and edge changes on every interactive element, and a menu, popover or tooltip leaving, on --ease-step | button, row, link, chip, menu */\n  --dur-base: 160ms; /* menus, popovers, selects, tooltips and toasts in, opacity only; they leave on the shorter --dur-fast | menu, popover, toast */\n  --dur-slow: 180ms; /* dialogs and sheets: opacity, plus --sheet-shift for a sheet | dialog, sheet */\n  --dur-spin: 800ms; /* one turn of a pending ring (--ease-spin) | spinner, button, input, progress ring, send button */\n  --dur-run: 1000ms; /* one turn of the running status arc (animate-run) | status arc */\n  --dur-slide: 1200ms; /* one pass of the indeterminate progress segment (animate-slide) | progress bar */\n  --ease-spin: linear; /* the pending ring turns smoothly | animate-spin */\n  --thumb-lift: 0%; /* how much ink the selected segment takes beyond paper; the dark theme raises it | surface-thumb */\n  --thumb-ring-alpha: 0; /* the ink alpha of the selected segment's 1px ring; the dark theme raises it | elev-thumb */\n  --skeleton-step: 0%; /* how much ink the skeleton fill takes beyond the grey field; the dark theme raises it | skeleton */\n  --dur-skeleton-delay: 150ms; /* wait before a skeleton shows, so fast loads never flash one | skeleton swap */\n  --dur-skeleton-hold: 400ms; /* shortest time a shown skeleton stays, so it never blinks | skeleton swap */\n  --toast-read-base: 3000ms; /* reading time every toast gets | toast */\n  --toast-read-char: 60ms; /* reading time per character of title and description | toast */\n  --toast-read-action: 3000ms; /* extra time when the toast carries an action | toast */\n  --toast-read-min: 4000ms; /* shortest a toast stays | toast */\n  --toast-read-max: 12000ms; /* longest a toast stays before it waits for the person | toast */\n  --scale-press: 0.98; /* the scale a pressed button or chip settles at | button, chip */\n  --ease-step: cubic-bezier(0.2, 0, 0, 1); /* the standard curve for every state change: hover, press, chip toggle, row select, tab switch | every interactive element */\n  --sheet-shift: 8px; /* how far a sheet travels from its edge as it appears | sheet */\n\n  /* == Layers == */\n  --z-raised: 10; /* a part lifted over its siblings inside one component | sticky table, data grid and dialog header and footer, focused tab, segment or grouped button, resize handles, item actions, avatar badge, select scroll arrows, code editor gutter, message time, conversation scroll button, attachment link */\n  --z-above: 20; /* a part that sits over a raised part | dialog close over its sticky header, resizable value label, attachment actions over its link, condensed page header */\n  --z-cover: 30; /* a layer over every part of its component | nested dialog dim, focused attachment link */\n  --z-drop: 40; /* a layer over a whole component while a file is dragged over it, or a bar floating over the page; under every overlay | attachment drop zone, bulk action bar */\n  --z-overlay: 50; /* every portalled layer; one layer, so the one opened last sits on top by DOM order | dialog, sheet, popover, menu, select, combobox, tooltip, toast, chart tooltip, mobile sidebar, skip link */\n\n  /* == Code == */\n  --code-string-alpha: 0.80; /* the alpha of ink in a string; the dark theme lowers it so strings part from plain code | code */\n  --code-comment-alpha: 0.66; /* the alpha of ink in a comment; --code-comment is 5.3:1 on --surface-card in both themes | code */\n}\n\n/* Derived tokens. Declared on every element that changes a channel, so they recompute there. */\n.quartz, .quartz [data-surface] {\n  /* == Surface == */\n  --ink: oklch(var(--ink-c)); /* solid ink | primary text, primary button */\n  --paper: oklch(var(--paper-c)); /* solid paper | page background */\n  --surface-canvas: oklch(var(--canvas-c)); /* the cool fog an app sits on, behind its cards and frames | app background, docs preview */\n  --surface-page: var(--paper); /* paper: the ground of every card, frame and panel | card, table, dialog */\n  --surface-card: oklch(var(--grey-c)); /* the well: the grey field inside a frame for code, logs, shell output and read-only values; never a container | well, code block, log body */\n  --surface-frame: color-mix(in oklch, var(--surface-card) 55%, var(--paper)); /* a panel's outer frame: lighter than the well, so a page of panels stays bright | panel, overlay shell */\n  --surface-raised: var(--paper); /* a container inside a grey card | table inside card, menu */\n  --surface-hover: oklch(var(--ink-c) / 0.05); /* row and item hover | row, menu item, ghost button */\n  --surface-selected: oklch(var(--ink-c) / 0.09); /* selected row with no kind, one step past hover | table, data table, tree */\n  --surface-pressed: oklch(var(--ink-c) / 0.08); /* active press | row, ghost button */\n  --surface-inverse: var(--ink); /* a pressed chip or highlighted item on the page's own channels; whole panels use data-surface=\"inverse\" | chip, segmented control */\n  --surface-tile: oklch(var(--ink-c) / 0.08); /* a media square behind an image or file icon, ink at 8% | attachment media */\n  --surface-overlay: oklch(var(--ink-c) / 0.24); /* dialog backdrop | dialog, sheet */\n\n  /* == Text == */\n  --text-1: var(--ink); /* primary text, and the only text on marks and fields | everything */\n  --text-2: oklch(var(--ink-c) / 0.80); /* secondary text, 9.6:1 on --surface-page, 8.9:1 on --surface-card | descriptions, meta */\n  --text-3: oklch(var(--ink-c) / 0.66); /* tertiary text, 5.8:1 on --surface-page, 5.5:1 on --surface-card, the floor for readable text | timestamps, captions */\n  --text-disabled: oklch(var(--ink-c) / 0.40); /* disabled controls only, never required text | disabled */\n  --text-inverse: var(--paper); /* text on inverse surfaces | primary button, tooltip */\n  --text-on-field: oklch(var(--text-on-field-c)); /* text on any hue field or mark; fixed dark in both themes | field section, icon chip */\n\n  /* == Border == */\n  --border-hair: oklch(var(--ink-c) / 0.08); /* a divider where fields cannot separate | table rows, default border */\n  --border-faint: oklch(var(--ink-c) / 0.05); /* a divider inside a grey card | card rows */\n  --border-strong: oklch(var(--ink-c) / 0.12); /* the strongest hairline | input hover, outline button */\n  --border-control: oklch(var(--ink-c) / 0.50); /* the edge of an empty control, 3.4:1 on --surface-page, 3.3:1 on --surface-card (WCAG 1.4.11) | checkbox, radio, switch */\n  --border-focus: var(--ink); /* focus outline, always ink | every focusable */\n  --line-frame: oklch(var(--ink-c) / var(--line-frame-alpha)); /* the one outer edge of a component, 1px, a quiet grey | frame, overlay edge, open row rules */\n  --line-row: oklch(var(--ink-c) / 0.08); /* the rule between rows and under a header, 1px; decorative, since rows also differ by content and space | rule-row, rule-col */\n  --line-control: oklch(var(--ink-c) / 0.16); /* the quiet edge of a field, a secondary button and a chip; the label and placeholder identify the control, so it stays light | input, select, secondary button, chip, kbd */\n  --line-control-hover: oklch(var(--ink-c) / 0.32); /* that edge under the pointer or while open | input, select, secondary button */\n  --scrollbar-thumb: oklch(var(--ink-c) / 0.20); /* scrollbar thumb at rest | scroll area, scrollbar-color */\n\n  /* == Elevation == */\n  --surface-thumb: color-mix(in oklch, var(--paper), oklch(var(--ink-c)) var(--thumb-lift)); /* the selected segment: paper on the grey track in light, paper mixed with ink in dark so it reads lighter than the track | segmented control */\n  --focus-halo: 0 0 0 3px oklch(var(--ink-c) / 0.08); /* a field with the cursor: a soft ink halo around its ink edge, eased in | input, select, combobox, date picker, OTP, code editor, composer */\n  --elev-control: 0 1px 2px -1px oklch(var(--text-on-field-c) / calc(var(--shadow-alpha) * 0.6)); /* the lift under a paper control, so a button or field sits on the page instead of being drawn on it | secondary button, input, select, chip */\n  --elev-none: 0 0 0 0 transparent; /* no lift, for a control that sits flat: disabled and read-only fields | field, select, checkbox, radio, switch, otp */\n  --elev-thumb: 0 0 0 1px oklch(var(--ink-c) / var(--thumb-ring-alpha)), 0 1px 2px oklch(var(--text-on-field-c) / calc(var(--shadow-alpha) * 0.5)); /* the selected segment lifted off its grey track; in dark a 1px ring joins the shadow | segmented control */\n  --elev-overlay: 0 0 0 1px var(--line-frame), 0 12px 24px -12px oklch(var(--text-on-field-c) / var(--shadow-alpha)); /* the overlay's edge plus one short shadow | menu, popover, select, dialog, sheet */\n\n  /* == Accent slot == */\n  --accent-mark: var(--ink); /* default when no kind is set | icon chip, bar fill */\n  --accent-field: var(--surface-card); /* default field | section field */\n  --accent-wash: var(--surface-selected); /* default selection wash, distinct from hover | selected row */\n  --accent-tint: var(--surface-selected); /* default label ground, neutral | kind label */\n  --accent-label: var(--text-1); /* default label word, ink | kind label */\n  --accent-line: var(--ink); /* default chart line and outline; a kind sets its line step | line chart, sparkline, radar, bar outline */\n  --accent-on-field: var(--text-1); /* text on the accent field: ink by default, dark on a hue in both themes | field section, banner */\n\n  /* == Button == */\n  --button-primary: var(--ink); /* dark on light, light on dark | primary button */\n  /* The key: a button as a lit object, one light from the top, layered on one element. body is the fill, lit-to-shade;\n     body-hover fades in over it (::before) as the light turns up; edge stacks the top lip, the bottom base, a hairline\n     inner rim, the outer ring and two short drops; edge-press sinks it; sheen (::after) is the soft dome on the top half\n     and a 1px glint along the top edge. */\n  --key-primary-body: linear-gradient(180deg, color-mix(in oklch, var(--ink) 84%, white), color-mix(in oklch, var(--ink) 94%, black)); /* ink lit from the top | primary button */\n  --key-primary-body-hover: linear-gradient(180deg, color-mix(in oklch, var(--ink) 76%, white), color-mix(in oklch, var(--ink) 90%, white)); /* the light turned up | primary hover */\n  --key-primary-edge: inset 0 2px 0 -1px oklch(1 0 0 / 0.2), inset 0 -2px 0 -1px oklch(0 0 0 / 0.3), inset 0 0 0 1px color-mix(in oklch, var(--ink) 88%, black), 0 1px 1px oklch(var(--text-on-field-c) / calc(var(--shadow-alpha) * 1.1)), 0 2px 5px -2px oklch(var(--text-on-field-c) / calc(var(--shadow-alpha) * 1.5)); /* ring drawn inside (the same box as a secondary or a field), the lip and base just inside it, two drops | primary button */\n  --key-primary-edge-press: inset 0 0 0 1px color-mix(in oklch, var(--ink) 88%, black), inset 0 1px 2px oklch(0 0 0 / 0.42); /* pushed in: the lift becomes an inner shadow | primary active */\n  --key-primary-sheen: linear-gradient(90deg, transparent 14%, oklch(1 0 0 / 0.42) 50%, transparent 86%) top / 100% 1px no-repeat, linear-gradient(180deg, oklch(1 0 0 / 0.1), oklch(1 0 0 / 0) 55%); /* glint line and top dome | primary button */\n  --key-secondary-body: var(--paper); /* flat paper, the same surface as a field, so a secondary button and an input beside it read as one family | secondary button */\n  --key-secondary-body-hover: oklch(var(--ink-c) / 0.03); /* a faint wash fading in over the paper on hover | secondary button */\n  --key-secondary-edge: var(--elev-control); /* the same one-pixel lift as a field; the key-secondary utility adds the ring from --frame-color | secondary button */\n  --key-secondary-edge-press: inset 0 1px 2px oklch(var(--ink-c) / 0.12); /* pushed in; the utility adds the ring | secondary active */\n  --key-secondary-sheen: none; /* no sheen: secondary stays as quiet as a field | secondary button */\n  --button-primary-hover: oklch(var(--ink-c) / 0.86); /* primary hover | primary button */\n  --button-secondary: oklch(var(--grey-c)); /* the grey field button | secondary button */\n  --button-secondary-hover: color-mix(in oklch, oklch(var(--grey-c)), oklch(var(--ink-c)) 7%); /* secondary hover on the page: the grey button a step darker, so hover shows | secondary button */\n  --button-ghost: transparent; /* ghost rest on paper | ghost button */\n  --button-ghost-hover: oklch(var(--ink-c) / 0.05); /* ghost hover | ghost button */\n  --surface-disabled: color-mix(in oklch, var(--paper), var(--ink) 8%); /* an opaque disabled fill, so the track behind a disabled thumb does not show through | slider thumb */\n  --ring-thumb: 0 0 0 2px var(--paper); /* the paper gap around a slider thumb, so it reads over the filled track | slider */\n\n  /* == Chart == */\n  --chart-ink-2: oklch(var(--ink-c) / 0.66); /* second ink series, 5.8:1 on --surface-page | multi-series chart without kinds */\n  --cell-quiet: oklch(var(--ink-c) / 0.07); /* an empty or zero cell in a heat strip or calendar grid | heatmap, status bar */\n\n  /* == Motion == */\n  --surface-skeleton: color-mix(in oklch, oklch(var(--grey-c)), oklch(var(--ink-c)) var(--skeleton-step)); /* the skeleton fill: the grey field, one step stronger in the dark theme | skeleton box */\n  --stale-opacity: 0.6; /* content that is reloading, still shown and still readable, 5:1 of ink at 60% | skeleton swap region while it reloads */\n  --dim-opacity: 0.4; /* content set aside while something else is the point: a muted legend entry, a dimmed series, a tool row in shell mode, a disabled thumbnail, a disabled primary key | chart legend, chart series, prompt input, attachment */\n\n\n  /* == Code == */\n  --code-text: var(--ink); /* identifiers, punctuation | code */\n  --code-string: oklch(var(--ink-c) / var(--code-string-alpha)); /* strings | code */\n  --code-comment: oklch(var(--ink-c) / var(--code-comment-alpha)); /* comments | code */\n  --code-prompt: oklch(var(--ink-c) / 0.40); /* the $ in shell snippets | snippet */\n}\n\n/* Kind map. The product maps its kinds to the five slots here, and only here. Kinds without a row\n   (projects, workspaces) stay ink. Traces belong to runs;\n   tools belong to agents.\n   Each row is an @scope, so when kinds nest the nearest data-kind wins by scope proximity, not by the\n   order of these rows. `:scope [data-surface]` keeps the kind on a surface inside it, which the derived\n   block would otherwise reset. Status rows come last, so data-status beats data-kind on one element.\n   aria-invalid=\"true\" sets the fail slot the same way data-status=\"fail\" does, so an invalid control\n   reads --accent-wash and --accent-mark without naming the fail hue. A field box (Input, the combobox\n   field and chips, the time field) holding an invalid control takes the slot too, because the box, not the\n   bare control, paints the field. */\n@scope (.quartz [data-kind=\"agent\"]) { :scope[data-kind], :scope [data-surface] { --accent-mark: var(--hue-1-mark); --accent-field: var(--hue-1-field); --accent-wash: var(--hue-1-wash); --accent-line: var(--hue-1-line); --accent-tint: var(--hue-1-tint); --accent-label: var(--hue-1-label); --accent-on-field: var(--text-on-field); } }\n@scope (.quartz [data-kind=\"key\"]) { :scope[data-kind], :scope [data-surface] { --accent-mark: var(--hue-2-mark); --accent-field: var(--hue-2-field); --accent-wash: var(--hue-2-wash); --accent-line: var(--hue-2-line); --accent-tint: var(--hue-2-tint); --accent-label: var(--hue-2-label); --accent-on-field: var(--text-on-field); } }\n@scope (.quartz [data-kind=\"run\"]) { :scope[data-kind], :scope [data-surface] { --accent-mark: var(--hue-3-mark); --accent-field: var(--hue-3-field); --accent-wash: var(--hue-3-wash); --accent-line: var(--hue-3-line); --accent-tint: var(--hue-3-tint); --accent-label: var(--hue-3-label); --accent-on-field: var(--text-on-field); } }\n@scope (.quartz [data-kind=\"deploy\"]) { :scope[data-kind], :scope [data-surface] { --accent-mark: var(--hue-4-mark); --accent-field: var(--hue-4-field); --accent-wash: var(--hue-4-wash); --accent-line: var(--hue-4-line); --accent-tint: var(--hue-4-tint); --accent-label: var(--hue-4-label); --accent-on-field: var(--text-on-field); } }\n@scope (.quartz [data-kind=\"model\"]) { :scope[data-kind], :scope [data-surface] { --accent-mark: var(--hue-5-mark); --accent-field: var(--hue-5-field); --accent-wash: var(--hue-5-wash); --accent-line: var(--hue-5-line); --accent-tint: var(--hue-5-tint); --accent-label: var(--hue-5-label); --accent-on-field: var(--text-on-field); } }\n@scope (.quartz [data-status=\"warn\"]) { :scope[data-status], :scope [data-surface] { --accent-mark: var(--warn-mark); --accent-field: var(--warn-field); --accent-wash: var(--warn-wash); --accent-line: var(--warn-line); --accent-tint: var(--warn-field); --accent-label: var(--text-on-field); --accent-on-field: var(--text-on-field); } }\n@scope (.quartz [data-status=\"fail\"]) { :scope[data-status], :scope [data-surface] { --accent-mark: var(--fail-mark); --accent-field: var(--fail-field); --accent-wash: var(--fail-wash); --accent-line: var(--fail-line); --accent-tint: var(--fail-field); --accent-label: var(--text-on-field); --accent-on-field: var(--text-on-field); } }\n@scope (.quartz :is([aria-invalid=\"true\"], :is([data-slot=\"input\"], [data-slot=\"combobox-input-group\"], [data-slot=\"combobox-chips\"], [data-slot=\"time-field\"]):has([data-control]:is([aria-invalid=\"true\"], [data-invalid])))) { :scope, :scope [data-surface] { --accent-mark: var(--fail-mark); --accent-field: var(--fail-field); --accent-wash: var(--fail-wash); --accent-line: var(--fail-line); --accent-tint: var(--fail-field); --accent-label: var(--text-on-field); --accent-on-field: var(--text-on-field); } }\n\n/* Surfaces. data-surface names what an element is painted as, and the derived tokens recompute on it.\n   - card: a grey well; secondary fills and inline code inside it flip to paper. No Quartz component sets it: Card is a paper frame\n     with no surface, so nothing inside a Card flips, and a skeleton, an avatar or a time in it reads as on the page.\n   - raised: a paper container inside a card, such as a menu or a command list. It declares no flip of its\n     own, so the derived block resets the card flip and fields inside read grey again.\n   - overlay: a dialog, sheet or popover panel on paper. Like raised, it resets the card flip; components\n     also use it as a hook for in-data-[surface=overlay] styling.\n   - paper and ink: always light and always dark, whatever the theme.\n   - inverse: the opposite of the page. Ink on a light page, paper in the dark theme and inside an ink\n     section. Tooltips, the chart tooltip and the bulk action bar use it. Toasts are paper with a frame and an overlay shadow, not inverse.\n   - page: the page's own channels, as a marker for in-data-[surface=page] styling. */\n.quartz [data-surface=\"card\"] { --surface-raised: var(--paper); --button-secondary: var(--paper); --button-secondary-hover: color-mix(in oklch, oklch(var(--paper-c)), oklch(var(--ink-c)) 4%); }\n/* An overlay popup that renders inside a card, a portal that was not lifted out or a menu in a story, would\n   inherit the card flip and paint its secondary fills paper on a paper panel. These slots reset those tokens to the\n   page's own values, whether or not the popup was portalled. Fields are paper everywhere, so they need no flip. */\n.quartz [data-surface=\"card\"] :is([data-slot=\"popover-content\"], [data-slot=\"popover-info-content\"], [data-slot=\"dropdown-menu-content\"], [data-slot=\"dropdown-menu-sub-content\"], [data-slot=\"select-content\"], [data-slot=\"combobox-content\"], [data-slot=\"filter-bar-select-content\"], [data-slot=\"date-picker-popup\"], [data-slot=\"time-field-popup\"], [data-slot=\"table-row-actions-content\"], [data-slot=\"dialog-content\"], [data-slot=\"sheet-content\"]) {\n  --surface-raised: var(--paper); --button-secondary: oklch(var(--grey-c));\n  --button-secondary-hover: color-mix(in oklch, oklch(var(--grey-c)), oklch(var(--ink-c)) 7%);\n}\n\n/* Dark theme. Ink and paper swap channels: deep navy paper on a darker canvas, near-white ink. Marks and fields keep their\n   values, so text on them stays --text-on-field; washes become deep tints of the same hue and lines take\n   the marks, which clear 3:1 on the dark page and the dark card. [data-surface=\"ink\"] is the same swap\n   for one always-dark section, and [data-surface=\"paper\"] swaps back inside it.\n   The theme comes from .quartz[data-theme=\"dark\"] or from an ancestor, [data-theme=\"dark\"] or .dark as most apps\n   set it on <html>; .quartz[data-theme=\"light\"] opts out of a dark ancestor. The ancestor sits in :where(), so\n   each selector weighs the same as its .quartz[data-theme=\"dark\"] twin and the paper block below still wins.\n   color-scheme follows each block, so native scrollbars, date fields and autofill match the surface.\n   [data-surface=\"inverse\"] takes the dark channels on a light page and the light channels in the dark\n   theme or inside ink, so it is always the opposite of what surrounds it. The second block is more\n   specific than the first, which is how the inverse flips back.\n   Dark-only notes. fail-wash drops from chroma 0.080 to 0.060 so red on graphite stops shouting, ink on it\n   is still 13:1. skeleton-step mixes 8% ink into the skeleton fill, 1.5:1 on the dark page where the grey field alone gave 1.1:1. code-string and\n   code-comment sit further from code-text than the light pair: against the dark card the three steps are\n   1.8:1 and 2.8:1 apart, close to the light theme's 1.8:1 and 2.9:1, and the comment is 5.3:1 on its field.\n   Keep this block free of semicolons in comments, lib/tokens.ts reads it with a regex. */\n.quartz[data-theme=\"dark\"], .quartz [data-surface=\"ink\"], .quartz [data-surface=\"inverse\"],\n:where([data-theme=\"dark\"], .dark) .quartz:not([data-theme=\"light\"]),\n:where([data-theme=\"dark\"], .dark) .quartz:not([data-theme=\"light\"]) [data-surface=\"paper\"] [data-surface=\"inverse\"],\n.quartz[data-theme=\"dark\"] [data-surface=\"paper\"] [data-surface=\"inverse\"], .quartz [data-surface=\"ink\"] [data-surface=\"paper\"] [data-surface=\"inverse\"] {\n  color-scheme: dark;\n  --ink-c: 96.5% 0.006 250;\n  --paper-c: 18.5% 0.016 262;\n  --grey-c: 23.5% 0.018 262;\n  --canvas-c: 15% 0.014 262;\n  --hue-1-wash: oklch(31% 0.060 195);\n  --hue-2-wash: oklch(31% 0.050 320);\n  --hue-3-wash: oklch(31% 0.080 250);\n  --hue-4-wash: oklch(31% 0.090 290);\n  --hue-5-wash: oklch(31% 0.055 160);\n  --hue-1-tint: oklch(30% 0.045 195);\n  --hue-1-label: oklch(88% 0.055 195);\n  --hue-2-tint: oklch(30% 0.045 320);\n  --hue-2-label: oklch(88% 0.055 320);\n  --hue-3-tint: oklch(30% 0.045 250);\n  --hue-3-label: oklch(88% 0.055 250);\n  --hue-4-tint: oklch(30% 0.045 290);\n  --hue-4-label: oklch(88% 0.055 290);\n  --hue-5-tint: oklch(30% 0.045 160);\n  --hue-5-label: oklch(88% 0.055 160);\n  --warn-text: oklch(80% 0.130 68);\n  --fail-text: oklch(76% 0.140 26);\n  --warn-wash: oklch(31% 0.055 68);\n  --fail-wash: oklch(29% 0.060 26);\n  --skeleton-step: 8%;\n  --code-string-alpha: 0.72;\n  --code-comment-alpha: 0.54;\n  --hue-1-line: var(--hue-1-mark);\n  --hue-2-line: var(--hue-2-mark);\n  --hue-3-line: var(--hue-3-mark);\n  --hue-4-line: var(--hue-4-mark);\n  --hue-5-line: var(--hue-5-mark);\n  --warn-line: var(--warn-mark);\n  --fail-line: var(--fail-mark);\n  --button-ghost: oklch(var(--ink-c) / 0.10); /* white at 10% on ink */\n  --button-ghost-hover: oklch(var(--ink-c) / 0.16);\n  --surface-pressed: oklch(var(--ink-c) / 0.28); /* white at 28% on ink, above the 16% hover so a press reads darker than hover */\n  --shadow-alpha: 0.6; /* a shadow on ink needs more weight to read */\n  --line-frame-alpha: 0.20;\n  --thumb-lift: 20%;\n  --thumb-ring-alpha: 0.16;\n}\n:where([data-theme=\"dark\"], .dark) .quartz:not([data-theme=\"light\"]) [data-surface=\"paper\"],\n:where([data-theme=\"dark\"], .dark) .quartz:not([data-theme=\"light\"]) [data-surface=\"inverse\"],\n.quartz[data-theme=\"dark\"] [data-surface=\"paper\"], .quartz [data-surface=\"ink\"] [data-surface=\"paper\"],\n.quartz[data-theme=\"dark\"] [data-surface=\"inverse\"], .quartz [data-surface=\"ink\"] [data-surface=\"inverse\"] {\n  color-scheme: light;\n  --ink-c: 20% 0.024 262;\n  --paper-c: 99.7% 0.001 250;\n  --grey-c: 95.6% 0.004 255;\n  --canvas-c: 99.1% 0.002 250;\n  --hue-1-wash: oklch(96.5% 0.040 195);\n  --hue-2-wash: oklch(96% 0.030 320);\n  --hue-3-wash: oklch(94.5% 0.020 250);\n  --hue-4-wash: oklch(95% 0.025 290);\n  --hue-5-wash: oklch(96% 0.035 160);\n  --hue-1-tint: oklch(92% 0.070 195);\n  --hue-1-label: oklch(38% 0.075 195);\n  --hue-2-tint: oklch(92% 0.045 320);\n  --hue-2-label: oklch(38% 0.055 320);\n  --hue-3-tint: oklch(92% 0.035 250);\n  --hue-3-label: oklch(38% 0.120 250);\n  --hue-4-tint: oklch(92% 0.045 290);\n  --hue-4-label: oklch(38% 0.120 290);\n  --hue-5-tint: oklch(92% 0.050 160);\n  --hue-5-label: oklch(38% 0.080 160);\n  --warn-text: oklch(49% 0.100 68);\n  --fail-text: oklch(51% 0.180 26);\n  --warn-wash: oklch(96% 0.028 68);\n  --fail-wash: oklch(94.5% 0.027 26);\n  --hue-1-line: oklch(60% 0.100 195);\n  --hue-2-line: oklch(58% 0.075 320);\n  --hue-3-line: oklch(52% 0.150 250);\n  --hue-4-line: oklch(54% 0.150 290);\n  --hue-5-line: oklch(52% 0.090 160);\n  --warn-line: oklch(62% 0.132 68);\n  --fail-line: oklch(60% 0.236 26);\n  --shadow-alpha: 0.20;\n  --skeleton-step: 0%;\n  --code-string-alpha: 0.80;\n  --code-comment-alpha: 0.66;\n  --button-ghost: transparent;\n  --button-ghost-hover: oklch(var(--ink-c) / 0.05);\n  --surface-pressed: oklch(var(--ink-c) / 0.08);\n  --line-frame-alpha: 0.14;\n  --thumb-lift: 0%;\n  --thumb-ring-alpha: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .quartz { --dur-base: 0ms; --dur-slow: 0ms; --sheet-shift: 0px }\n}\n/* A wrapper that sets data-force-reduced-motion (styles.css) gets the same values. */\n.quartz [data-force-reduced-motion] { --dur-base: 0ms; --dur-slow: 0ms; --sheet-shift: 0px }\n",
      "type": "registry:file",
      "target": "@components/quartz/tokens.css"
    },
    {
      "path": "registry/quartz/base.css",
      "content": "/* Scoped base for Quartz. Replaces Tailwind preflight inside .quartz only; imported before the utilities. */\n\n.quartz {\n  min-height: 100dvh;\n  background: var(--surface-canvas);\n  color: var(--text-1);\n  font: var(--type-body);\n  font-variation-settings: var(--width-normal);\n  letter-spacing: var(--tracking-text);\n  text-wrap: pretty;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  /* Light here; tokens.css sets dark on the dark theme and ink surfaces, and light again on paper inside them. */\n  color-scheme: light;\n}\n/* The reset sits in the base layer, beside Tailwind's own preflight, so a project's layered utilities (mx-auto,\n   px-4) beat it, and Quartz's unlayered ones still do. What must win over a page's own rules stays out of the layer:\n   the scope element, prose links, the selection colour, the focus ring and the iOS zoom guard. */\n@layer base {\n  .quartz :where(*, ::before, ::after) { box-sizing: border-box; border: 0 solid var(--line-row); margin: 0; padding: 0; }\n  .quartz :where(h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, pre) { margin: 0; font: inherit; }\n  .quartz :where(ul, ol) { list-style: none; }\n  .quartz :where(a) { color: inherit; text-decoration: inherit; }\n  .quartz :where(button, input, select, textarea) { font: inherit; letter-spacing: inherit; color: inherit; background: transparent; }\n  .quartz :where(button, [role=\"button\"]) { cursor: pointer; }\n  .quartz :where(button:disabled, [aria-disabled=\"true\"]) { cursor: not-allowed; }\n  /* max-width: 100% shrinks an SVG layer with no width of its own (a 0x0 overflow-visible overlay) to nothing,\n     so an SVG marked overflow-visible skips it. Any other SVG layer that must overflow its box takes max-w-none. */\n  .quartz :where(img, video, canvas, svg:not(.overflow-visible, [overflow=\"visible\"])) { display: block; max-width: 100%; }\n  .quartz :where(svg.overflow-visible, svg[overflow=\"visible\"]) { display: block; }\n  .quartz :where(table) { border-collapse: collapse; }\n  .quartz :where(code, kbd, samp, pre) { font-family: var(--font-mono); }\n  /* Every duration, count and value lines up: tabular figures in table cells and time and data elements. */\n  .quartz :where(td, th, time, data, output) { font-variant-numeric: tabular-nums; }\n  /* Every interactive element declares its transition, so no control cuts while its neighbour tweens.\n     Hover is 120ms (--dur-fast) on the standard curve; a press answers in 60ms (--dur-press). Components override at will. */\n  .quartz :where(a, button, summary, input, select, textarea, label, [role=\"button\"], [role=\"tab\"], [role=\"menuitem\"], [role=\"option\"], [role=\"switch\"], [role=\"checkbox\"], [role=\"radio\"]) {\n    transition-property: color, background-color, border-color, outline-color, text-decoration-color, box-shadow, opacity;\n    transition-duration: var(--dur-fast);\n    transition-timing-function: var(--ease-step);\n  }\n  .quartz :where(a, button, [role=\"button\"]):where(:active) { transition-duration: var(--dur-press); }\n}\n/* Prose links (inside [data-prose]) are underlined at rest: 1px at a 4px offset in text-3, darkening to ink\n   on hover. Their focus ring hugs the text with the soft corner and 2px of side padding. */\n.quartz :where([data-prose]) a:where(:not([data-slot])) {\n  text-decoration: underline 1px var(--text-3);\n  text-underline-offset: 4px;\n  border-radius: var(--radius-soft);\n  padding-inline: 2px;\n  margin-inline: -2px;\n}\n@media (hover: hover) { .quartz :where([data-prose]) a:where(:not([data-slot])):hover { text-decoration-color: var(--ink); color: var(--text-1); } }\n.quartz ::selection { background: var(--hue-3-field); color: var(--text-on-field); }\n/* The ring's colour is set at rest, so an element that transitions outline-color never fades its ring in from\n   the text colour. */\n.quartz :where(*, ::before, ::after) { outline-color: var(--border-focus); }\n/* Focus is always a --line-focus outline in --border-focus, --focus-offset out: one treatment for every element.\n   Two classes of specificity beat an app's global a:focus-visible. Where the ring must sit elsewhere, the focus-ring\n   and focus-ring-inset utilities (styles.css) draw the same ring. */\n.quartz :where(*):is(:focus-visible, [data-force-focus-visible]) { outline: var(--line-focus) solid var(--border-focus); outline-offset: var(--focus-offset); }\n/* A bare control inside a box ([data-control]) draws no ring: the box turns its edge ink with has-[[data-control]:focus],\n   so the icons and units in the box sit inside the ring (trap/field-affix-focus). */\n.quartz :where([data-control]):is(:focus-visible, [data-force-focus-visible]) { outline: none; }\n\n/* iOS WebKit zooms the page when a field under 16px takes focus. On a coarse pointer every text field is at\n   least 16px, whatever its type role says. Two classes of specificity beat a type-* utility on the field. */\n@media (pointer: coarse) {\n  .quartz input:not([type=\"checkbox\"], [type=\"radio\"], [type=\"range\"], [type=\"button\"], [type=\"submit\"], [type=\"file\"], [type=\"color\"]),\n  .quartz textarea,\n  .quartz select { font-size: max(16px, 1em); }\n}\n",
      "type": "registry:file",
      "target": "@components/quartz/base.css"
    },
    {
      "path": "registry/quartz/styles.css",
      "content": "/* Quartz's Tailwind entry. Import it once, in the root layout, as its own stylesheet, and put the quartz class\n   on the element that holds Quartz UI (usually body).\n\n   Scoping, so none of this reaches the rest of your app:\n   - No preflight. base.css applies inside .quartz only.\n   - The theme is `inline reference`: utilities compile to var(--quartz-token) and nothing is written to\n     :root, so your own --color-*, --space-* and --font-* tokens stay as they are.\n   - Utilities come only from the folders the @source lines name (source(none)). Installed in a project, those are\n     Quartz's folders and the project's app, pages, src and components, so a Quartz class in your own code works,\n     and the utilities are nested under :where(.quartz, [data-system=\"quartz\"]), so none reaches markup outside it.\n   - base.css comes before the utilities, so a utility beats a base rule of the same specificity.\n   - Utilities are unlayered on purpose. Unlayered rules beat every layer, so layered utilities would lose\n     to an app's unlayered global `a` and `button` rules. */\n\n@import \"./tokens.css\";\n@import \"./base.css\";\n:where(.quartz, [data-system=\"quartz\"]) {\n  @tailwind utilities source(none);\n}\n\n@source \"../../app\";\n@source \"../../pages\";\n@source \"../../src\";\n@source \"../../components\";\n@source \"../../lib/quartz\";\n@source not \"../../lib/quartz/lint\";\n\n/* dark: matches wherever the ink channel is light: in the dark theme, set on .quartz or on an ancestor as\n   [data-theme=\"dark\"] or an app's .dark, and inside ink. .quartz[data-theme=\"light\"] under a dark ancestor stays\n   light. An inverse surface is dark on a light page and light in the dark theme or inside ink, so it joins the\n   first list and leaves through the last :not(). */\n@custom-variant dark (&:where(:is(:is([data-theme=\"dark\"], [data-theme=\"dark\"] *, .dark *):not(.quartz[data-theme=\"light\"], .quartz[data-theme=\"light\"] *), [data-surface=\"ink\"], [data-surface=\"ink\"] *, [data-surface=\"inverse\"], [data-surface=\"inverse\"] *):not(:is(.quartz[data-theme=\"dark\"], :is([data-theme=\"dark\"], .dark) .quartz:not([data-theme=\"light\"]), [data-surface=\"ink\"]) :is([data-surface=\"inverse\"], [data-surface=\"inverse\"] *))));\n\n/* A component's state can be shown without the pointer or keyboard, for a style guide, a story or a screenshot\n   test, by setting data-force-hover, data-force-focus, data-force-focus-visible or data-force-active on its\n   root. These variants answer to the attribute as well as the real pseudo-class, so a forced state is the\n   component's own style, never a copy that drifts. Hover keeps Tailwind's guard: it only fires on devices that can hover.\n   Because they are selector variants, the compound forms answer too: has-focus-visible: matches a\n   descendant carrying data-force-focus-visible, and group-hover/x: a group carrying data-force-hover. */\n@custom-variant hover { @media (hover: hover) { &:hover { @slot; } } &[data-force-hover] { @slot; } }\n@custom-variant focus { &:focus { @slot; } &[data-force-focus] { @slot; } }\n@custom-variant focus-visible { &:focus-visible { @slot; } &[data-force-focus-visible] { @slot; } }\n@custom-variant active { &:active { @slot; } &[data-force-active] { @slot; } }\n\n/* touch: a screen with no hover or a coarse pointer, one spelling for both checks (touch:opacity-100, touch:hidden). */\n@custom-variant touch { @media (hover: none) { @slot; } @media (pointer: coarse) { @slot; } }\n\n/* A wrapper with data-force-reduced-motion shows its contents as under reduced motion, for the same uses.\n   motion-reduce: answers to it as well as the media query, motion-safe: stands down under it,\n   and tokens.css zeroes the same durations there as under the query. Forced colors has no such hook:\n   the browser repaints with system colors and drops backgrounds and shadows, which CSS cannot imitate,\n   so forced-colors stays a media variant and is checked with browser emulation. */\n@custom-variant motion-reduce { @media (prefers-reduced-motion: reduce) { @slot; } &:where([data-force-reduced-motion], [data-force-reduced-motion] *) { @slot; } }\n@custom-variant motion-safe { @media (prefers-reduced-motion: no-preference) { &:not(:where([data-force-reduced-motion], [data-force-reduced-motion] *)) { @slot; } } }\n\n@theme inline reference {\n  --*: initial;\n\n  --breakpoint-sm: 640px;\n  --breakpoint-md: 768px;\n  --breakpoint-lg: 1024px;\n  --breakpoint-xl: 1280px;\n\n  /* Container widths for max-w-* and @container variants. --*: initial removes Tailwind's defaults,\n     so they are declared again here, at Tailwind's values. */\n  --container-3xs: 16rem;\n  --container-2xs: 18rem;\n  --container-xs: 20rem;\n  --container-sm: 24rem;\n  --container-md: 28rem;\n  --container-lg: 32rem;\n  --container-xl: 36rem;\n  --container-2xl: 42rem;\n  --container-3xl: 48rem;\n  --container-4xl: 56rem;\n  --container-5xl: 64rem;\n  --container-6xl: 72rem;\n  --container-7xl: 80rem;\n  --container-field-group: 448px; /* width where responsive fields sit side by side | field */\n  --container-popup: var(--popup-max); /* tallest a list popup grows before it scrolls | select, combobox, menu */\n  --container-overlay-sm: var(--overlay-sm);\n  --container-overlay: var(--overlay);\n  --container-overlay-lg: var(--overlay-lg);\n  --container-popover: var(--popover);\n  --container-toast: var(--toast-width);\n\n  /* Tailwind's other theme-backed families that --*: initial wiped and that Quartz pages use: aspect-video\n     (a 16:9 skeleton or media area) and leading-tight. aspect-square and the other fixed ratios need no\n     theme value. */\n  --aspect-video: 16 / 9;\n  --leading-tight: 1.25;\n\n  /* 4px base: p-1 is --space-1, p-4 is --space-4. */\n  --spacing: var(--space-1);\n\n  /* The semantic names generic components expect (background, card, muted, accent), pointed at Quartz roles. A card is still the grey field until Card becomes the frame;\n     muted is the well. */\n  --color-background: var(--surface-page);\n  --color-foreground: var(--text-1);\n  --color-card: var(--surface-card);\n  --color-card-foreground: var(--text-1);\n  --color-popover: var(--surface-raised);\n  --color-popover-foreground: var(--text-1);\n  --color-primary: var(--button-primary);\n  --color-primary-foreground: var(--text-inverse);\n  --color-secondary: var(--button-secondary);\n  --color-secondary-foreground: var(--text-1);\n  --color-muted: var(--surface-card);\n  --color-muted-foreground: var(--text-2);\n  --color-accent: var(--surface-hover);\n  --color-accent-foreground: var(--text-1);\n  --color-destructive: var(--fail-mark);\n  --color-destructive-foreground: var(--text-on-field);\n  --color-border: var(--line-row);\n  --color-input: var(--line-control);\n  --color-ring: var(--border-focus);\n  --color-sidebar: var(--surface-page);\n  --color-sidebar-foreground: var(--text-1);\n  --color-sidebar-accent: var(--surface-hover);\n  --color-sidebar-border: var(--border-hair);\n\n  /* Quartz's own roles. */\n  --color-paper: var(--paper);\n  --color-ink: var(--ink);\n  --color-page: var(--surface-page);\n  --color-surface: var(--surface-card);\n  --color-raised: var(--surface-raised);\n  --color-hover: var(--surface-hover);\n  --color-selected: var(--surface-selected);\n  --color-tile: var(--surface-tile);\n  --color-cell-quiet: var(--cell-quiet);\n  --color-chart-ink-2: var(--chart-ink-2);\n  --color-accent-line: var(--accent-line);\n  --color-control: var(--border-control);\n  --color-pressed: var(--surface-pressed);\n  --color-inverse: var(--surface-inverse);\n  --color-overlay: var(--surface-overlay);\n  --color-text-1: var(--text-1);\n  --color-text-2: var(--text-2);\n  --color-text-3: var(--text-3);\n  --color-text-disabled: var(--text-disabled);\n  --color-text-inverse: var(--text-inverse);\n  --color-on-field: var(--text-on-field);\n  --color-hair: var(--border-hair);\n  --color-faint: var(--border-faint);\n  --color-strong: var(--border-strong);\n  --color-accent-mark: var(--accent-mark);\n  --color-accent-field: var(--accent-field);\n  --color-accent-wash: var(--accent-wash);\n  --color-accent-tint: var(--accent-tint);\n  --color-accent-label: var(--accent-label);\n  --color-warn-text: var(--warn-text);\n  --color-fail-text: var(--fail-text);\n  --color-on-accent-field: var(--accent-on-field);\n  --color-warn: var(--warn-mark);\n  --color-fail: var(--fail-mark);\n  --color-button-primary-hover: var(--button-primary-hover);\n  --color-button-secondary-hover: var(--button-secondary-hover);\n  --color-ghost: var(--button-ghost);\n  --color-ghost-hover: var(--button-ghost-hover);\n  --color-well: var(--surface-card);\n  --color-frame: var(--line-frame);\n  --color-line-row: var(--line-row);\n  --color-transparent: transparent;\n  --color-current: currentColor;\n\n  --font-sans: var(--font-sans);\n  --font-mono: var(--font-mono);\n\n  --font-weight-normal: var(--weight-body);\n  --font-weight-medium: var(--weight-medium);\n  --font-weight-semibold: var(--weight-strong);\n  --font-weight-bold: 700;\n\n  /* The usual size names (text-sm, text-base) mapped to Quartz roles (size, line-height). Prefer the type-* utilities. */\n  --text-xs: 12px;\n  --text-xs--line-height: 16px;\n  --text-sm: 14px;\n  --text-sm--line-height: 20px;\n  --text-base: 16px;\n  --text-base--line-height: 22px;\n  --text-lg: 20px;\n  --text-lg--line-height: 24px;\n  --text-xl: 24px;\n  --text-xl--line-height: 28px;\n  --text-2xl: 32px;\n  --text-2xl--line-height: 36px;\n  --text-3xl: 40px;\n  --text-3xl--line-height: 44px;\n\n  --tracking-display: var(--tracking-display);\n  --tracking-heading: var(--tracking-heading);\n  --tracking-body: var(--tracking-body);\n  --tracking-text: var(--tracking-text);\n  --tracking-normal: 0em;\n\n  --radius-none: var(--radius-0);\n  --radius-inner: var(--radius-inner);\n  --radius-soft: var(--radius-soft);\n  --radius-frame: var(--radius-frame);\n  --radius-xs: var(--radius-inner);\n  --radius-sm: var(--radius-inner);\n  --radius-md: var(--radius-soft);\n  --radius-lg: var(--radius-frame);\n  --radius-xl: var(--radius-frame);\n  --radius-full: var(--radius-full);\n\n  /* No shadows except overlays. shadow-xs and shadow-sm stay empty so a default shadow draws nothing. */\n  --shadow-xs: 0 0 #0000;\n  --shadow-sm: 0 0 #0000;\n  --shadow-md: var(--elev-overlay);\n  --shadow-lg: var(--elev-overlay);\n  --shadow-overlay: var(--elev-overlay);\n\n  --ease-step: var(--ease-step);\n\n  --animate-run: quartz-spin var(--dur-run) linear infinite;\n  --animate-slide: quartz-slide var(--dur-slide) var(--ease-step) infinite;\n  --animate-spin: quartz-spin var(--dur-spin) var(--ease-spin) infinite;\n}\n\n/* One utility per type role. Text at 14px and below tracks at 0 (--tracking-text); 16px text takes\n   --tracking-body and display sizes stay negative. Numeric roles turn on tabular figures. The font shorthand resets the width axis, so set it after. */\n@utility type-display-xl { font: var(--type-display-xl); letter-spacing: var(--tracking-display); font-variation-settings: var(--width-normal); }\n@utility type-display-lg { font: var(--type-display-lg); letter-spacing: var(--tracking-display); font-variation-settings: var(--width-normal); }\n@utility type-display { font: var(--type-display); letter-spacing: var(--tracking-display); font-variation-settings: var(--width-normal); }\n@utility type-heading-lg { font: var(--type-heading-lg); letter-spacing: var(--tracking-heading); font-variation-settings: var(--width-normal); }\n@utility type-heading { font: var(--type-heading); letter-spacing: var(--tracking-heading); font-variation-settings: var(--width-normal); }\n@utility type-heading-sm { font: var(--type-heading-sm); letter-spacing: var(--tracking-heading); font-variation-settings: var(--width-normal); }\n@utility type-heading-xs { font: var(--type-heading-xs); letter-spacing: var(--tracking-heading); font-variation-settings: var(--width-normal); }\n@utility type-body-lg { font: var(--type-body-lg); letter-spacing: var(--tracking-body); font-variation-settings: var(--width-normal); }\n@utility type-body { font: var(--type-body); letter-spacing: var(--tracking-text); font-variation-settings: var(--width-normal); }\n@utility type-body-sm { font: var(--type-body-sm); letter-spacing: var(--tracking-text); font-variation-settings: var(--width-normal); }\n@utility type-button { font: var(--type-button); letter-spacing: var(--tracking-body); font-variation-settings: var(--width-normal); }\n@utility type-label { font: var(--type-label); letter-spacing: var(--tracking-text); font-variation-settings: var(--width-normal); }\n@utility type-label-sm { font: var(--type-label-sm); letter-spacing: var(--tracking-text); font-variation-settings: var(--width-normal); font-feature-settings: var(--features-data); }\n@utility type-code { font: var(--type-code); letter-spacing: 0; font-variant-numeric: tabular-nums; }\n@utility type-tag { font: var(--type-tag); letter-spacing: 0; font-variant-numeric: tabular-nums; }\n@utility type-code-sm { font: var(--type-code-sm); letter-spacing: 0; font-variant-numeric: tabular-nums; }\n@utility type-code-touch { font: var(--type-code-touch); letter-spacing: 0; font-variant-numeric: tabular-nums; }\n@utility type-code-display { font: var(--type-code-display); font-feature-settings: var(--features-data); }\n@utility type-stat-xl { font: var(--type-stat-xl); letter-spacing: 0; font-variation-settings: var(--width-normal); font-feature-settings: var(--features-data); }\n@utility type-stat-lg { font: var(--type-stat-lg); letter-spacing: 0; font-variation-settings: var(--width-normal); font-feature-settings: var(--features-data); }\n@utility type-stat { font: var(--type-stat); letter-spacing: 0; font-variation-settings: var(--width-normal); font-feature-settings: var(--features-data); }\n@utility type-state-word { font: var(--type-state-word); letter-spacing: var(--tracking-text); font-variation-settings: var(--width-normal); }\n@utility data { font-feature-settings: var(--features-data); }\n\n/* Focus. base.css rings every :focus-visible element; these are that same ring, from the same tokens, for the\n   places it has to sit elsewhere. focus-ring: on a box that shows the focus of the bare control inside it\n   (has-[[data-control]:focus-visible]:focus-ring), an open trigger or a cell the grid has made current.\n   focus-ring-inset: the ring inside the element's own edge, where a container would clip it or a neighbour's shared\n   line would collide with an offset ring (cells in a strip, rows, menu items, day cells). */\n@utility focus-ring { outline: var(--line-focus) solid var(--border-focus); outline-offset: var(--focus-offset); }\n@utility focus-ring-inset { outline: var(--line-focus) solid var(--border-focus); outline-offset: calc(var(--line-focus) * -1); }\n/* touch-target: a coarse pointer gets a 44px (--control-lg) hit area centred on a smaller control, drawn on ::after so the\n   layout and the fine-pointer look stay as they are. The host must be positioned and must not use ::after itself (a key\n   button does, so it keeps its own size). Neighbours closer than 44px overlap, and the later one in the DOM takes the tap. */\n@utility touch-target {\n  @media (pointer: coarse) {\n    &::after { content: \"\"; position: absolute; top: 50%; left: 50%; translate: -50% -50%; width: max(100%, var(--control-lg)); height: max(100%, var(--control-lg)); }\n  }\n}\n\n/* focus-ring-ink: on an ink-filled cell that sits edge to edge (a checked segment, a pressed group member, a selected\n   day, a focused chip), where an ink ring would vanish into the fill. A 2px paper ring 4px inside the cell, leaving 2px\n   of ink outside it, so the ring reads ink, paper, ink: 17.1:1 for paper on ink in light, the same pair flipped in dark. */\n@utility focus-ring-ink { outline: var(--line-focus) solid var(--paper); outline-offset: calc(var(--line-focus) * -2); }\n\n/* Lines. A component draws its edges on pseudo-elements, so a line never takes layout and neighbours can meet on one\n   pixel. An element that sets --frame-color recolours its own edge; nothing else changes a frame's colour. */\n\n/* frame: the one edge of a component's root. The root isolates, so its edge sits over its own rows, washes and sticky\n   heads, and clips, so a row's wash follows the rounded corner. Put it on a wrapper that does not scroll: a ::before inside\n   a scroller scrolls away with the content. --frame-radius is registered as non-inheriting, so a frame reads only\n   the radius set on itself and never the one a parent frame set for its own corners. */\n@property --frame-radius { syntax: \"*\"; inherits: false; }\n@utility frame {\n  position: relative;\n  isolation: isolate;\n  overflow: clip;\n  border-radius: var(--frame-radius, var(--radius-frame));\n  &::before {\n    content: \"\"; position: absolute; inset: 0; pointer-events: none; z-index: var(--z-cover);\n    border: 1px solid var(--frame-color, var(--line-frame)); border-radius: inherit;\n  }\n}\n\n/* frame-shared: cells side by side with no gap (chip strip, toolbar, segmented control, pagination). Each cell draws\n   its start, top and bottom edges and the last cell also its end, so no pixel is painted twice and a translucent edge\n   keeps its own alpha. Only the outer corners round. */\n@utility frame-shared {\n  position: relative;\n  border-radius: var(--radius-0);\n  &::before {\n    content: \"\"; position: absolute; inset: 0; pointer-events: none;\n    border: 1px solid var(--frame-color, var(--line-control)); border-inline-end-width: 0; border-radius: inherit;\n  }\n  &:first-child { border-start-start-radius: var(--radius-soft); border-end-start-radius: var(--radius-soft); }\n  &:last-child { border-start-end-radius: var(--radius-soft); border-end-end-radius: var(--radius-soft); }\n  &:last-child::before { border-inline-end-width: 1px; }\n}\n\n/* frame-shared-y: frame-shared for a column of cells (a vertical button group). Each cell draws its start, end and top\n   edges and the last cell also its bottom; only the top and bottom outer corners round. */\n@utility frame-shared-y {\n  position: relative;\n  border-radius: var(--radius-0);\n  &::before {\n    content: \"\"; position: absolute; inset: 0; pointer-events: none;\n    border: 1px solid var(--frame-color, var(--line-control)); border-block-end-width: 0; border-radius: inherit;\n  }\n  &:first-child { border-start-start-radius: var(--radius-soft); border-start-end-radius: var(--radius-soft); }\n  &:last-child { border-end-start-radius: var(--radius-soft); border-end-end-radius: var(--radius-soft); }\n  &:last-child::before { border-block-end-width: 1px; }\n}\n\n/* frame-ink: an ink edge on one control or cell, for hover, pressed and open (hover:frame-ink, aria-pressed:frame-ink).\n   In a strip the cell also draws its end edge over its neighbour's start edge and rises above it, so both its sides\n   read ink. */\n@utility frame-ink {\n  --frame-color: var(--ink);\n  z-index: var(--z-raised);\n  &:where(.frame-shared:not(:last-child))::before { border-inline-end-width: 1px; inset-inline-end: -1px; }\n  &:where(.frame-shared-y:not(:last-child))::before { border-block-end-width: 1px; inset-block-end: -1px; }\n}\n\n/* frame-out: an edge 1px outside the box, for an element that must sit on its neighbour's line. On a translucent line\n   it stacks, so use it where it replaces the line below it (a selected tab over its panel, which hides the panel's\n   line under the tab with paper). */\n@utility frame-out {\n  position: relative;\n  &::before {\n    content: \"\"; position: absolute; inset: -1px; pointer-events: none; z-index: var(--z-raised);\n    border: 1px solid var(--frame-color, var(--line-frame)); border-radius: inherit;\n  }\n}\n\n/* key: a button as a lit object (tokens --key-*). One element, one light from the top: the body (background), the\n   edge (box-shadow: lip, base, rim, ring, drops) and a sheen (::after: a 1px glint and a soft top dome). Press sinks\n   it: the lift becomes an inner shadow and the sheen dims. The primary adds a hover light on ::before (the body-hover\n   fading in); the secondary takes its hover wash as a background layer, so ::before stays free for frame-shared when\n   it joins a button group. The label stays above the layers through isolation. Disabled drops the light layers. */\n@utility key {\n  isolation: isolate;\n  &::after { content: \"\"; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; z-index: -1; transition: opacity var(--dur-fast) var(--ease-step); }\n  &:active:not([data-disabled])::after { opacity: 0.4; }\n  &[data-disabled]::after { display: none; }\n  @media (forced-colors: active) { &::after { display: none; } }\n}\n@utility key-primary {\n  background: var(--key-primary-body); box-shadow: var(--key-primary-edge);\n  &::before { content: \"\"; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; z-index: -1; opacity: 0; background: var(--key-primary-body-hover); transition: opacity var(--dur-fast) var(--ease-step); }\n  &:hover:not([data-disabled])::before { opacity: 1; }\n  &[data-disabled]::before { display: none; }\n  @media (forced-colors: active) { &::before { display: none; } }\n  &::after { background: var(--key-primary-sheen); }\n  &:active:not([data-disabled]) { box-shadow: var(--key-primary-edge-press); }\n}\n@utility key-secondary {\n  background: var(--key-secondary-body); box-shadow: inset 0 0 0 1px var(--frame-color, var(--line-control)), var(--key-secondary-edge);\n  transition: background-color var(--dur-fast) var(--ease-step);\n  &:hover:not([data-disabled]) { background: linear-gradient(var(--key-secondary-body-hover), var(--key-secondary-body-hover)), var(--key-secondary-body); }\n  &::after { background: var(--key-secondary-sheen); }\n  &:active:not([data-disabled]) { box-shadow: inset 0 0 0 1px var(--frame-color, var(--line-control)), var(--key-secondary-edge-press); }\n  /* A toggle that is on is an ink key held down. */\n  &[data-pressed]:not([data-disabled]) { background: var(--key-primary-body); box-shadow: var(--key-primary-edge-press); }\n}\n\n/* control-edge: the 1px edge of a control that cannot take a pseudo-element (input, textarea, select) or that sits\n   alone (a field box, a trigger). An inset shadow, so it never takes layout. It reads --frame-color on the element\n   itself, so hover:[--frame-color:var(--line-frame)] or an invalid state recolours it. It is not a token because a var() inside a\n   token resolves where the token is declared, so a --frame-color set on the control would never reach it. */\n@utility control-edge { box-shadow: inset 0 0 0 1px var(--frame-color, var(--line-control)), var(--control-lift, var(--elev-control)); }\n\n/* rule-row: the faint rule under a row or a header. The last row drops it, because the frame's edge is right below.\n   An open row ([data-open], one per list) takes a soft wash and no ink lines. */\n@utility rule-row {\n  box-shadow: inset 0 -1px 0 var(--line-row);\n  &:last-child { box-shadow: none; }\n  &:where([data-open]) { background-color: var(--surface-hover); }\n}\n/* rule-col: the same rule on a cell's start edge, for cells side by side inside one frame (a stat strip, a toolbar in a\n   table). rule-top: the rule above a footer. */\n@utility rule-col { box-shadow: inset 1px 0 0 var(--line-row); &:dir(rtl) { box-shadow: inset -1px 0 0 var(--line-row); } }\n@utility rule-top { box-shadow: inset 0 1px 0 var(--line-row); }\n/* rule-row-frame: the frame-weight rule under a bar that stands alone (a page header, a sidebar header, a tab strip), so it\n   keeps its line as the last child, where rule-row would drop it. */\n@utility rule-row-frame { box-shadow: inset 0 -1px 0 var(--line-frame); }\n\n/* wash-row: the faint fail wash on a row (a failed table, list, log or timeline row): the accent wash at 40%, and 60% under the\n   pointer (wash-row-hover, as hover:wash-row-hover). It reads --accent-wash on the element itself, since a status scope sets that\n   on the row, which is why this is a utility and not a token. */\n@utility wash-row { background-color: color-mix(in oklab, var(--accent-wash) 40%, transparent); }\n@utility wash-row-hover { background-color: color-mix(in oklab, var(--accent-wash) 60%, transparent); }\n\n/* frame-head: the one header of a framed component (Panel, Card, table, chart, code, log, timeline, JSON, a response's\n   code block). 40px (--row), the title and meta 16px from the start edge, and one action at the end at xs (24px,\n   wrap it in ButtonSize xs or use icon-xs) 8px from the end edge: it takes the 8px as soon as it holds a button, radio or combobox.\n   frame-head-action is that action slot. The rule under it is the caller's (rule-row), because a Panel's header sits on\n   the grey and has none. */\n@utility frame-head {\n  display: flex; align-items: center; gap: var(--space-2); min-width: 0; flex-shrink: 0;\n  min-height: var(--row); padding-inline: var(--space-4);\n  &:has(:is(button, [role=\"radio\"], [role=\"combobox\"])) { padding-inline-end: var(--space-2); }\n}\n@utility frame-head-action { margin-inline-start: auto; display: flex; flex-shrink: 0; align-items: center; gap: var(--space-1); }\n\n/* frame-foot: the one footer of a framed component, 44px (--control-lg) with the text 16px from the start edge and\n   actions at sm (28px, wrap in ButtonSize sm) 8px from the end edge. Content sits at the start; add justify-end where it\n   holds only actions. Buttons keep their size on a touch screen too: the 44px footer already gives them room, and a\n   footer of 44px-tall buttons reads as a phone form, not the card. The rule above is the caller's (rule-top). */\n@utility frame-foot {\n  display: flex; align-items: center; gap: var(--space-2); min-width: 0;\n  min-height: var(--control-lg); padding: var(--space-2) var(--space-4);\n  &:has(button) { padding-inline-end: var(--space-2); }\n}\n\n/* The one list recipe. Every popup that lists things (dropdown menu, select, combobox, command, the table's menus, breadcrumb,\n   button group, filter bar, the prompt's @ and / list) draws its rows, labels and rules from these four, so a row is the same\n   32px (--row-sm) tall, 8px from its edges, with a 8px gap and 16px icons wherever it appears. The base is wrapped in :where()\n   so any class on the item (pe-8 for a trailing check, items-start for a second line) still wins. The surface and the motion of\n   the popup are lib/overlay's, not these.\n   menu-popup: the geometry of a popup that scrolls as one block, at least --menu-min wide, 4px inside its edge.\n   menu-item: a row. The highlighted one (data-highlighted, set by the list itself) takes the hover wash; data-variant=\"destructive\"\n   reads in the fail word at rest and takes the fail wash. A coarse pointer grows it to the 44px touch target; forced colours paints\n   the highlighted row with Highlight and the disabled one with GrayText. A leading icon steps back to text-2.\n   menu-label: the heading of a group of rows. menu-separator: the hairline between groups, edge to edge of the 4px inset. */\n@utility menu-popup {\n  :where(&) { min-width: var(--menu-min); max-width: min(var(--overlay), var(--available-width)); max-height: var(--available-height); padding: var(--space-1); overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; }\n  &:focus-visible { outline: none; }\n}\n@utility menu-item {\n  :where(&) {\n    position: relative; display: flex; align-items: center; gap: var(--space-2); min-height: var(--row-sm);\n    padding: calc(var(--space-1) * 1.5) var(--space-2); border-radius: var(--radius-inner);\n    font: var(--type-label); letter-spacing: var(--tracking-text); font-variation-settings: var(--width-normal);\n    color: var(--text-1); cursor: default; user-select: none; outline: none;\n  }\n  :where(& > svg) { flex-shrink: 0; pointer-events: none; color: var(--text-2); }\n  &[data-highlighted] { background-color: var(--surface-hover); }\n  &[data-variant=\"destructive\"] { color: var(--fail-text); }\n  &[data-variant=\"destructive\"] > svg { color: inherit; }\n  &[data-variant=\"destructive\"][data-highlighted] { background-color: var(--accent-wash); }\n  &[data-disabled] { cursor: not-allowed; color: var(--text-disabled); }\n  @media (pointer: coarse) { :where(&) { min-height: var(--control-lg); } }\n  @media (forced-colors: active) {\n    &[data-disabled] { color: GrayText; }\n    &[data-highlighted] { forced-color-adjust: none; background-color: Highlight; color: HighlightText; }\n    &[data-highlighted] svg { color: HighlightText; }\n  }\n}\n@utility menu-label {\n  :where(&) {\n    padding: var(--space-2) var(--space-2) var(--space-1); color: var(--text-3);\n    font: var(--type-label-sm); letter-spacing: var(--tracking-text); font-variation-settings: var(--width-normal); font-feature-settings: var(--features-data);\n  }\n}\n@utility menu-separator {\n  :where(&) { height: 1px; margin: var(--space-1) calc(var(--space-1) * -1); background-color: var(--line-row); }\n  @media (forced-colors: active) { background-color: CanvasText; }\n}\n\n/* search-row: the search field that sits inside a component (Command, the prompt's command list, a log's filter, a JSON tree's\n   search), not in a form. One row, --row (40px) tall, with the icon 16px from the start edge in text-3, 8px to the text, and\n   room at the end for a count and a clear button. It has no box of its own, so focus is the field's ink edge drawn inside the\n   row (the same ink as a field's edge, with no halo to clip). Put it on the label or div that holds the icon and the input;\n   mark the input data-control (base.css rings every other focusable) and give it search-field. The rule under the row is the\n   caller's (rule-row) and the edge replaces it while the field has focus. */\n@utility search-row {\n  :where(&) {\n    display: flex; align-items: center; gap: var(--space-2); min-height: var(--row); min-width: 0; flex-shrink: 0;\n    padding-inline: var(--space-4) var(--space-2);\n    transition: box-shadow var(--dur-fast) var(--ease-step);\n  }\n  &:has([data-control]:focus-visible) { box-shadow: inset 0 0 0 1px var(--border-focus); }\n  :where(& > svg) { flex-shrink: 0; color: var(--text-3); }\n}\n@utility search-field {\n  :where(&) {\n    height: 100%; min-width: 0; flex: 1 1 0%; background: transparent; color: var(--text-1);\n    font: var(--type-label); letter-spacing: var(--tracking-text); font-variation-settings: var(--width-normal);\n  }\n  &::placeholder { color: var(--text-3); }\n  &::-webkit-search-cancel-button { display: none; }\n  /* 16px stops iOS from zooming into the field on focus. */\n  @media (pointer: coarse) { font-size: 16px; }\n}\n\n/* well: the grey field, only for code, output and read-only values inside a frame. No line of its own. Padding is the\n   caller's, px-4 py-3 by default. */\n@utility well { background-color: var(--surface-card); }\n\n/* An indeterminate progress bar: a third of the track slides across it once per --dur-slide, then starts again (animate-slide). */\n@keyframes quartz-slide { from { transform: translateX(-100%); } to { transform: translateX(300%); } }\n\n/* A running mark is a 3/4 arc turning once per --dur-run (animate-run). */\n@keyframes quartz-spin { to { transform: rotate(1turn); } }\n\n/* Native scrollbars take the thumb role, so a thin scrollbar reads in both themes. */\n.quartz, .quartz * { scrollbar-color: var(--scrollbar-thumb) transparent; }\n\n/* Toast (ui/toast.tsx): the drain line shrinks to nothing over the toast's timeout. */\n@keyframes quartz-toast-drain { from { scale: 1 1; } to { scale: 0 1; } }\n\n/* fade-y and fade-x: a scroller fades to nothing over --fade-edge at each edge that has more behind it, as its data-fade says\n   (start, end or both). Something that measures the scroll position sets data-fade (lib/overlay's useScrollFade for a\n   vertical list, the tab list for a sideways one). fade-x reads the sides from --fade-from and --fade-to (left and right\n   unless the element sets them, as an RTL tab list does). Put it on the element that scrolls, never on a popup, where the\n   mask would also cut the shadow. */\n@utility fade-y {\n  &[data-fade=\"end\"] { mask-image: linear-gradient(to bottom, black calc(100% - var(--fade-edge)), transparent); }\n  &[data-fade=\"start\"] { mask-image: linear-gradient(to top, black calc(100% - var(--fade-edge)), transparent); }\n  &[data-fade=\"both\"] { mask-image: linear-gradient(to bottom, transparent, black var(--fade-edge), black calc(100% - var(--fade-edge)), transparent); }\n}\n@utility fade-x {\n  &[data-fade=\"start\"] { mask-image: linear-gradient(to var(--fade-to, right), transparent, black var(--fade-edge)); }\n  &[data-fade=\"end\"] { mask-image: linear-gradient(to var(--fade-from, left), transparent, black var(--fade-edge)); }\n  /* Two masks intersect, so both edges fade. */\n  &[data-fade=\"both\"] {\n    mask-image: linear-gradient(to var(--fade-to, right), transparent, black var(--fade-edge)), linear-gradient(to var(--fade-from, left), transparent, black var(--fade-edge));\n    mask-composite: intersect; -webkit-mask-composite: source-in;\n  }\n}\n\n/* scroll-fade-y: a scrolling list fades to nothing over --fade-edge at each edge that has more behind it.\n   Two scroll-driven animations ride two registered lengths into one mask, the top one opening over the first\n   24px of scroll and the bottom one closing over the last 24px. A list that does not scroll has no active\n   timeline, so both lengths stay 0 and nothing fades; a browser without scroll timelines shows no fade at\n   all. Put it on the element that scrolls, never on a popup, where the mask would also cut the shadow. */\n@property --fade-top { syntax: \"<length>\"; inherits: false; initial-value: 0px; }\n@property --fade-bottom { syntax: \"<length>\"; inherits: false; initial-value: 0px; }\n@keyframes quartz-fade-top { from { --fade-top: 0px; } to { --fade-top: var(--fade-edge); } }\n@keyframes quartz-fade-bottom { from { --fade-bottom: var(--fade-edge); } to { --fade-bottom: 0px; } }\n@utility scroll-fade-y {\n  mask-image: linear-gradient(to bottom, transparent, black var(--fade-top), black calc(100% - var(--fade-bottom)), transparent);\n  @supports (animation-timeline: scroll()) {\n    animation: quartz-fade-top linear both, quartz-fade-bottom linear both;\n    animation-timeline: scroll(self), scroll(self);\n    animation-range: 0 var(--fade-edge), calc(100% - var(--fade-edge)) 100%;\n  }\n}\n\n",
      "type": "registry:file",
      "target": "@components/quartz/styles.css"
    }
  ]
}
