Remove accidentally-committed design-bundle/ artifact
Un-ignoring design-bundle/ in the previous commit picked up the leftover
directory from an earlier local run. There's no generator
for it anymore; it shouldn't have been tracked.
diff --git a/design-bundle/components/badge.html b/design-bundle/components/badge.html
deleted file mode 100644
index 39a6c93..0000000
--- a/design-bundle/components/badge.html
+++ /dev/null
@@ -1,1815 +0,0 @@
-<!-- @dsCard group="Core" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Badge</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Badge</h1>
-</header>
-<p class="ad-lead">Mono, uppercase, tracked — the catalog-label convention for status and meta values. An archivist's tag, not a badge asking for attention.</p>
-<p>Labels are catalog-style: short, mono, uppercase — <code>SAVED</code>, <code>RECOMMENDED</code>,
-<code>OVERDUE</code>. Never a click handler on one; a Badge is a label, not a button.</p>
-
-<p>A <code><span></code> is too generic to style bare — it shows up all over running prose
-for unrelated reasons — so Badge keeps one class. Tone is an attribute, not a
-modifier class.</p>
-
-<h2 id="tones">Tones</h2>
-
-<figure class="example">
-<figcaption>Tones</figcaption>
-<div>
-<span class="badge">Unassigned</span>
-<span class="badge" data-tone="accent">Draft</span>
-<span class="badge" data-tone="success">Saved</span>
-<span class="badge" data-tone="danger">Overdue</span>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><span class="badge">Unassigned</span>
-<span class="badge" data-tone="accent">Draft</span>
-<span class="badge" data-tone="success">Saved</span>
-<span class="badge" data-tone="danger">Overdue</span></code></pre>
-</details>
-</figure>
-
-<h2 id="in-a-set">In a set</h2>
-
-<figure class="example">
-<figcaption>Badge set</figcaption>
-<div>
-<div class="badge-set">
- <span class="badge" data-tone="accent">Recommended</span>
- <span class="badge">Every 2 weeks</span>
- <span class="badge" data-tone="danger">3d overdue</span>
-</div>
-</div>
-<details><summary>Markup</summary>
-<pre><code><div class="badge-set">
- <span class="badge" data-tone="accent">Recommended</span>
- <span class="badge">Every 2 weeks</span>
- <span class="badge" data-tone="danger">3d overdue</span>
-</div></code></pre>
-</details>
-</figure>
-
-<h2 id="rules">Rules</h2>
-
-<ul>
- <li><strong>A badge is never interactive.</strong> No click handlers, no <code><button></code>, no cursor
-change. If it does something, it is a button that happens to be small.</li>
- <li><strong>Two or three words at most.</strong> A badge that wraps is a sentence in the wrong clothes.</li>
- <li><strong><code>danger</code> means something needs attention, not that something failed.</strong> The
-source uses it for overdue, not for a system error — that is what prose is for.</li>
-</ul>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>span.badge</code></td><td></td><td>Required base.</td></tr>
- <tr><td><code>data-tone</code></td><td><code>accent | success | danger</code></td><td>Omit for the default neutral tone.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/button.html b/design-bundle/components/button.html
deleted file mode 100644
index 015e413..0000000
--- a/design-bundle/components/button.html
+++ /dev/null
@@ -1,1913 +0,0 @@
-<!-- @dsCard group="Core" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Button</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Button</h1>
-</header>
-<p class="ad-lead">A flat, quiet button that recedes rather than performs — no gradients, no shine. Five variants, three sizes, one geometry.</p>
-<h2 id="variants">Variants</h2>
-
-<p><code>default</code> is bordered and neutral. <code>primary</code> is the accent fill — one
-committing action per view, at most. <code>dark</code> is reserved for the single most
-committing action in a screen, typically a final Save; it should be rare.
-<code>ghost</code> has no border or fill, for dismissals and tertiary actions. <code>danger</code>
-is destructive and irreversible only.</p>
-
-<figure class="example">
-<figcaption>Variants</figcaption>
-<div>
-<button>Cancel</button>
-<button data-variant="primary">Save</button>
-<button data-variant="dark">Finish setup</button>
-<button data-variant="ghost">Dismiss</button>
-<button data-variant="danger">Delete</button>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><button>Cancel</button>
-<button data-variant="primary">Save</button>
-<button data-variant="dark">Finish setup</button>
-<button data-variant="ghost">Dismiss</button>
-<button data-variant="danger">Delete</button></code></pre>
-</details>
-</figure>
-
-<h2 id="sizes">Sizes</h2>
-
-<p>Sizes adjust padding only — the font stays on the type scale, it does not
-grow a step of its own.</p>
-
-<figure class="example">
-<figcaption>Sizes</figcaption>
-<div>
-<button data-variant="primary" data-size="sm">Small</button>
-<button data-variant="primary">Medium</button>
-<button data-variant="primary" data-size="lg">Large</button>
-</div>
-<details><summary>Markup</summary>
-<pre><code><button data-variant="primary" data-size="sm">Small</button>
-<button data-variant="primary">Medium</button>
-<button data-variant="primary" data-size="lg">Large</button></code></pre>
-</details>
-</figure>
-
-<h2 id="states">States</h2>
-
-<p>Disabled buttons drop to 50% opacity and keep their variant colors, so a
-disabled primary still reads as the primary.</p>
-
-<figure class="example">
-<figcaption>States</figcaption>
-<div>
-<button data-variant="primary" disabled="">Disabled</button>
-<button aria-disabled="true">Not yet available</button>
-</div>
-<details><summary>Markup</summary>
-<pre><code><button data-variant="primary" disabled="">Disabled</button>
-<button aria-disabled="true">Not yet available</button></code></pre>
-</details>
-</figure>
-
-<div class="ad-callout">
- <p class="type-label" style="margin-bottom: var(--ad-space-2xs); display:block;">disabled vs. aria-disabled</p>
- <p style="margin:0; font-size: var(--ad-step--1);">
- A <code>disabled</code> button is removed from the tab order, so a reader
- navigating by keyboard never learns it is there. When a button is
- temporarily unavailable and the reason matters, use
- <code>aria-disabled="true"</code> instead — it stays focusable and can
- carry an explanation.
- </p>
-</div>
-
-<h2 id="with-an-icon">With an icon</h2>
-
-<p>Pass an icon as the first child. The gap is <code>--ad-space-2xs</code>, set by the
-button itself.</p>
-
-<figure class="example">
-<figcaption>Icon</figcaption>
-<div>
-<button data-variant="primary">
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
- New
-</button>
-</div>
-<details><summary>Markup</summary>
-<pre><code><button data-variant="primary">
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
- New
-</button></code></pre>
-</details>
-</figure>
-
-<h2 id="groups">Groups</h2>
-
-<p><code>[role="group"]</code> is already the correct ARIA role for a toolbar of related
-buttons, so it doubles as the styling hook — no wrapper class.</p>
-
-<figure class="example">
-<figcaption>Button group</figcaption>
-<div>
-<div role="group" aria-label="View">
- <button data-size="sm">List</button>
- <button data-size="sm">Board</button>
- <button data-size="sm">Calendar</button>
-</div>
-</div>
-<details><summary>Markup</summary>
-<pre><code><div role="group" aria-label="View">
- <button data-size="sm">List</button>
- <button data-size="sm">Board</button>
- <button data-size="sm">Calendar</button>
-</div></code></pre>
-</details>
-</figure>
-
-<h2 id="full-width">Full width</h2>
-
-<figure class="example">
-<figcaption>Block</figcaption>
-<div data-layout="stack">
-<button data-variant="primary" data-block="">Take a photo</button>
-</div>
-<details><summary>Markup</summary>
-<pre><code><button data-variant="primary" data-block>Take a photo</button></code></pre>
-</details>
-</figure>
-
-<h2 id="links-that-act-like-buttons">Links that act like buttons</h2>
-
-<p>An <code><a></code> with <code>.btn</code> is fine when the thing it does is navigate. A <code><button></code>
-is required when it changes something. <code>.btn</code> exists only because a bare <code>a</code>
-selector would catch every ordinary prose link on the site — it is the one
-class Button needs, and only anchors reach for it.</p>
-
-<figure class="example">
-<figcaption>Anchor as button</figcaption>
-<div>
-<a class="btn" data-variant="primary" href="https://kejadlen.github.io/arbitrary-definitions-design-system/components/icon-button/">Next: IconButton</a>
-<a class="btn" data-variant="ghost" href="https://kejadlen.github.io/arbitrary-definitions-design-system/foundations/color/">Back to color</a>
-</div>
-<details><summary>Markup</summary>
-<pre><code><a class="btn" data-variant="primary" href="/arbitrary-definitions-design-system/components/icon-button/">Next: IconButton</a>
-<a class="btn" data-variant="ghost" href="/arbitrary-definitions-design-system/foundations/color/">Back to color</a></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>button</code></td><td></td><td>Required base. A bare <code><button></code> is styled directly — no class. Use <code><a class="btn"></code> instead when the control navigates.</td></tr>
- <tr><td><code>data-variant</code></td><td><code>primary | dark | ghost | danger</code></td><td>Omit for the default, bordered look.</td></tr>
- <tr><td><code>data-size</code></td><td><code>sm | lg</code></td><td>Omit for the default (medium) size. Padding only.</td></tr>
- <tr><td><code>data-block</code></td><td>boolean</td><td>Full width of its container.</td></tr>
- <tr><td><code>disabled</code></td><td>boolean</td><td>Removes the button from the tab order.</td></tr>
- <tr><td><code>aria-disabled</code></td><td><code>"true"</code></td><td>Looks disabled, stays focusable.</td></tr>
- <tr><td><code>[role="group"]</code></td><td></td><td>Wrap adjacent buttons in a group to join their borders and radii.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/card-row.html b/design-bundle/components/card-row.html
deleted file mode 100644
index b7b2b77..0000000
--- a/design-bundle/components/card-row.html
+++ /dev/null
@@ -1,1845 +0,0 @@
-<!-- @dsCard group="Core" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>CardRow</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>CardRow</h1>
-</header>
-<p class="ad-lead">A hairline-divided list row for use inside Card — entry lists, task lists, settings rows. The first row's top border removes itself automatically.</p>
-<p>CardRow is a bare <code><li></code> inside a <code><ul class="card"></code> — the divider styling
-comes entirely from the <code>.card > li</code> descendant selector, so there is no
-class of CardRow’s own.</p>
-
-<h2 id="basic">Basic</h2>
-
-<figure class="example">
-<figcaption>Rows</figcaption>
-<div>
-<ul class="card" style="max-width: 22rem;">
- <li>Renew passport</li>
- <li>Dentist checkup</li>
- <li>Rotate mattress</li>
-</ul>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><ul class="card" style="max-width: 22rem;">
- <li>Renew passport</li>
- <li>Dentist checkup</li>
- <li>Rotate mattress</li>
-</ul></code></pre>
-</details>
-</figure>
-
-<h2 id="clickable">Clickable</h2>
-
-<p>Wrap the row’s content in a real <code><button></code> or <code><a></code> when the row navigates
-or opens something — an accessible clickable row, not a <code><li></code> with a click
-handler and no keyboard support. It fills the row edge-to-edge and picks up
-a hover fill on its own; no <code>--clickable</code> modifier to remember.</p>
-
-<figure class="example">
-<figcaption>Clickable rows</figcaption>
-<div>
-<ul class="card" style="max-width: 22rem;">
- <li><button>Tax return 2025.pdf</button></li>
- <li><button>Warranty card.pdf</button></li>
-</ul>
-</div>
-<details><summary>Markup</summary>
-<pre><code><ul class="card" style="max-width: 22rem;">
- <li><button>Tax return 2025.pdf</button></li>
- <li><button>Warranty card.pdf</button></li>
-</ul></code></pre>
-</details>
-</figure>
-
-<h2 id="with-content-on-both-ends">With content on both ends</h2>
-
-<p>The row is a flex container — a leading icon, a two-line middle column, and a
-trailing mono value is the most common shape (see the Loop and Archive
-patterns for it in context).</p>
-
-<figure class="example">
-<figcaption>Leading icon, trailing meta</figcaption>
-<div>
-<ul class="card" style="max-width: 24rem;">
- <li>
- <span class="avatar" data-square="">
- <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 8 12 3 3 8v8l9 5 9-5V8Z" /><path d="M3 8l9 5 9-5M12 13v8" /></svg>
- </span>
- <div style="flex:1; min-width:0;">
- <div style="font-weight: 550;">Dishwasher manual</div>
- <div class="type-label" style="margin-top: 2px;">PDF · 2.1MB</div>
- </div>
- <span class="type-mono" style="color: var(--ad-color-text-tertiary);">2h</span>
- </li>
-</ul>
-</div>
-<details><summary>Markup</summary>
-<pre><code><ul class="card" style="max-width: 24rem;">
- <li>
- <span class="avatar" data-square>
- <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 8 12 3 3 8v8l9 5 9-5V8Z" /><path d="M3 8l9 5 9-5M12 13v8" /></svg>
- </span>
- <div style="flex:1; min-width:0;">
- <div style="font-weight: 550;">Dishwasher manual</div>
- <div class="type-label" style="margin-top: 2px;">PDF · 2.1MB</div>
- </div>
- <span class="type-mono" style="color: var(--ad-color-text-tertiary);">2h</span>
- </li>
-</ul></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>li</code></td><td></td><td>Required — a direct child of <code>ul.card</code>. No class of its own.</td></tr>
- <tr><td><code>li > button</code> / <code>li > a</code></td><td></td><td>Wrap the row's content to make it clickable, in place of an <code>onClick</code> prop.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/card.html b/design-bundle/components/card.html
deleted file mode 100644
index cfb0e1e..0000000
--- a/design-bundle/components/card.html
+++ /dev/null
@@ -1,1841 +0,0 @@
-<!-- @dsCard group="Core" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Card</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Card</h1>
-</header>
-<p class="ad-lead">Flat surface, hairline border, radius-lg. Elevation is opt-in, reserved for the one focused card in a view — a dialog, the primary capture card.</p>
-<p>A <code><div></code>/<code><article></code> is too generic to style bare, so Card keeps one
-sanctioned class. <code>[data-elevated]</code> is for the single most-elevated element on
-screen — never a whole grid of cards at once.</p>
-
-<h2 id="flat-vs-elevated">Flat vs. elevated</h2>
-
-<figure class="example">
-<figcaption>Flat and elevated</figcaption>
-<div data-surface="sunken">
-<div class="card" style="width: 14rem; padding: var(--ad-space-s);">Flat — the default.</div>
-<div class="card" data-elevated="" style="width: 14rem; padding: var(--ad-space-s);">Elevated — one per view.</div>
-</div>
-<details><summary>Markup</summary>
-<pre><code><div class="card" style="width: 14rem; padding: var(--ad-space-s);">Flat — the default.</div>
-<div class="card" data-elevated style="width: 14rem; padding: var(--ad-space-s);">Elevated — one per view.</div></code></pre>
-</details>
-</figure>
-
-<h2 id="as-a-content-tile">As a content tile</h2>
-
-<p>Used standalone (not as a row-list), <code>.card</code> is fine on its own — <code>.card-body</code>
-and <code>.card-footer</code> are two more sanctioned classes, for the one shape inside
-it that has no element of its own to hang a selector on.</p>
-
-<figure class="example">
-<figcaption>Content tile</figcaption>
-<div>
-<article class="card" style="max-width: 18rem;">
- <div class="card-body">
- <p class="type-label" style="margin:0;">Recommended</p>
- <h3 style="margin:0; font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans);">Rename the caution color</h3>
- <p style="margin:0; color: var(--ad-color-text-secondary); font-size: var(--ad-step--1);">Three people have called it "yellow" in review this month.</p>
- </div>
- <div class="card-footer">
- <button data-variant="primary" data-size="sm">Approve</button>
- <button data-variant="ghost" data-size="sm">Dismiss</button>
- </div>
-</article>
-</div>
-<details><summary>Markup</summary>
-<pre><code><article class="card" style="max-width: 18rem;">
- <div class="card-body">
- <p class="type-label" style="margin:0;">Recommended</p>
- <h3 style="margin:0; font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans);">Rename the caution color</h3>
- <p style="margin:0; color: var(--ad-color-text-secondary); font-size: var(--ad-step--1);">Three people have called it "yellow" in review this month.</p>
- </div>
- <div class="card-footer">
- <button data-variant="primary" data-size="sm">Approve</button>
- <button data-variant="ghost" data-size="sm">Dismiss</button>
- </div>
-</article></code></pre>
-</details>
-</figure>
-
-<h2 id="as-a-list--with-cardrow">As a list — with CardRow</h2>
-
-<p>Card’s most common job in this system is holding a list of
-<a href="https://kejadlen.github.io/arbitrary-definitions-design-system/components/card-row/">CardRow</a>s: entry lists, task
-lists, settings rows. In that shape Card is a real <code><ul class="card"></code> and
-CardRow is a bare <code><li></code> — the divider between rows comes from the <code>.card >
-li</code> descendant selector, no second class needed.</p>
-
-<figure class="example">
-<figcaption>Card of rows</figcaption>
-<div>
-<ul class="card" style="max-width: 22rem;">
- <li>Dishwasher manual</li>
- <li>Sofa receipt</li>
- <li>Passport scan</li>
-</ul>
-</div>
-<details><summary>Markup</summary>
-<pre><code><ul class="card" style="max-width: 22rem;">
- <li>Dishwasher manual</li>
- <li>Sofa receipt</li>
- <li>Passport scan</li>
-</ul></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>.card</code></td><td></td><td>Required base, on a <code><div></code>/<code><article></code> for a standalone tile or a <code><ul></code> for a list of rows.</td></tr>
- <tr><td><code>data-elevated</code></td><td>boolean</td><td>Applies <code>--ad-shadow-float</code>. One per view.</td></tr>
- <tr><td><code>> li</code></td><td></td><td>A CardRow, when Card is a <code><ul></code>. See <a href="https://kejadlen.github.io/arbitrary-definitions-design-system/components/card-row/">CardRow</a>.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/checkbox.html b/design-bundle/components/checkbox.html
deleted file mode 100644
index 7701288..0000000
--- a/design-bundle/components/checkbox.html
+++ /dev/null
@@ -1,1847 +0,0 @@
-<!-- @dsCard group="Forms" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Checkbox</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Checkbox</h1>
-</header>
-<p class="ad-lead">Native checkbox, tinted with the accent color. No hand-drawn box.</p>
-<h2 id="basic">Basic</h2>
-
-<p><code>input[type="checkbox"]</code> is the component — styled bare with <code>accent-color</code>
-rather than a custom box, so the browser draws its own check. This is a real
-reduction, not just a rename: it deletes the hand-drawn SVG-checkmark markup
-that a <code>.ad-choice__box</code> span used to need. The wrapping <code><label></code> is told
-apart from Field’s label structurally — it <code>:has()</code> a checkbox as a direct
-child — so it needs no class either.</p>
-
-<figure class="example">
-<figcaption>Checkbox</figcaption>
-<div>
-<label>
- <input type="checkbox" />
- Notify me
-</label>
-<label>
- <input type="checkbox" checked="" />
- Ship on merge
-</label>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><label>
- <input type="checkbox" />
- Notify me
-</label>
-<label>
- <input type="checkbox" checked="" />
- Ship on merge
-</label></code></pre>
-</details>
-</figure>
-
-<h2 id="disabled">Disabled</h2>
-
-<figure class="example">
-<figcaption>Disabled</figcaption>
-<div>
-<label>
- <input type="checkbox" disabled="" />
- Not available on this plan
-</label>
-</div>
-<details><summary>Markup</summary>
-<pre><code><label>
- <input type="checkbox" disabled="" />
- Not available on this plan
-</label></code></pre>
-</details>
-</figure>
-
-<h2 id="in-a-fieldset">In a fieldset</h2>
-
-<p><code><fieldset></code>/<code><legend></code> are styled bare too — they already mean this.</p>
-
-<figure class="example">
-<figcaption>Fieldset</figcaption>
-<div>
-<fieldset>
- <legend>Notify me about</legend>
- <label>
- <input type="checkbox" checked="" />
- Overdue tasks
- </label>
- <label>
- <input type="checkbox" />
- Weekly digest
- </label>
-</fieldset>
-</div>
-<details><summary>Markup</summary>
-<pre><code><fieldset>
- <legend>Notify me about</legend>
- <label>
- <input type="checkbox" checked="" />
- Overdue tasks
- </label>
- <label>
- <input type="checkbox" />
- Weekly digest
- </label>
-</fieldset></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>input[type="checkbox"]</code></td><td></td><td>Required base — no class. Tinted with <code>accent-color</code>.</td></tr>
- <tr><td><code>checked</code></td><td>boolean</td><td></td></tr>
- <tr><td><code>disabled</code></td><td>boolean</td><td></td></tr>
- <tr><td><code>label</code></td><td>text content</td><td>Wrap the input directly — <code>label:has(> input[type="checkbox"])</code> is what applies the row layout.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/dialog.html b/design-bundle/components/dialog.html
deleted file mode 100644
index 24b57cd..0000000
--- a/design-bundle/components/dialog.html
+++ /dev/null
@@ -1,1825 +0,0 @@
-<!-- @dsCard group="Feedback" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Dialog</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Dialog</h1>
-</header>
-<p class="ad-lead">A centered modal. Flat surface, no colored header, hairline dividers between title, body, and footer.</p>
-<p>Dialog is the native <code><dialog></code> element: a <code><header></code> for the title, a
-<code><footer></code> for the button row, and everything else in between is the body —
-no wrapper classes at all.</p>
-
-<p>The example below is shown with a plain <code>open</code> attribute, scoped to its own
-preview box rather than the real viewport-covering overlay, so it renders
-without JavaScript and can sit safely inside a documentation page. It
-centers itself using the browser’s own default <code><dialog></code> styling
-(<code>position: absolute; inset: 0; margin: auto</code>) against the preview box,
-which is why it needs that box to be <code>position: relative</code>. Call
-<code>.showModal()</code> in the consuming app for the real fixed-overlay behavior —
-a plain <code>open</code> attribute never paints a <code>::backdrop</code>, since that
-pseudo-element only exists for a dialog shown modally.</p>
-
-<figure class="example">
-<figcaption>Dialog</figcaption>
-<div data-layout="stack">
-<div class="dialog-demo">
- <dialog open="">
- <header>Delete series?</header>
- <p>This removes all of its task history. This cannot be undone.</p>
- <footer>
- <button>Cancel</button>
- <button data-variant="danger">Delete</button>
- </footer>
- </dialog>
-</div>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><dialog open>
- <header>Delete series?</header>
- <p>This removes all of its task history. This cannot be undone.</p>
- <footer>
- <button>Cancel</button>
- <button data-variant="danger">Delete</button>
- </footer>
-</dialog></code></pre>
-</details>
-</figure>
-
-<h2 id="without-a-footer">Without a footer</h2>
-
-<p>A body-only dialog for a notice rather than a decision.</p>
-
-<figure class="example">
-<figcaption>No footer</figcaption>
-<div data-layout="stack">
-<div class="dialog-demo" style="min-height: 14rem;">
- <dialog open="" style="width: 20rem;">
- <header>Backup complete</header>
- <p>412 files, 1.2GB, archived to the household drive.</p>
- </dialog>
-</div>
-</div>
-<details><summary>Markup</summary>
-<pre><code><dialog open style="width: 20rem;">
- <header>Backup complete</header>
- <p>412 files, 1.2GB, archived to the household drive.</p>
-</dialog></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>dialog</code></td><td></td><td>Required base. Call <code>.showModal()</code> to open it for real — a plain <code>open</code> attribute is for static, always-open documentation only.</td></tr>
- <tr><td><code>dialog > header</code></td><td></td><td>Optional — a body-only dialog omits it.</td></tr>
- <tr><td><code>dialog > footer</code></td><td></td><td>Optional. Usually a pair of Buttons — the least committing action first.</td></tr>
- <tr><td><code>dialog::backdrop</code></td><td></td><td>The dimmed overlay. Only renders once the dialog is shown via <code>.showModal()</code>.</td></tr>
- <tr><td><code>close</code> event</td><td></td><td>Fired on cancel — wire it, or a form's <code>method="dialog"</code>, instead of an <code>onClose</code> prop.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/field.html b/design-bundle/components/field.html
deleted file mode 100644
index 4d44b8e..0000000
--- a/design-bundle/components/field.html
+++ /dev/null
@@ -1,1861 +0,0 @@
-<!-- @dsCard group="Forms" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Field</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Field</h1>
-</header>
-<p class="ad-lead">The labeled field wrapper. Mono, uppercase, tracked label — the same catalog-label convention as Badge and type-label — with an optional hint.</p>
-<h2 id="basic">Basic</h2>
-
-<p>Field is a <code><label></code> that wraps its caption text together with the control —
-association is native, no <code>for</code>/<code>id</code> pair to keep in sync. A <code><label></code> plays
-three different roles in this system (this wrapper, Checkbox/Radio’s row,
-Switch’s row), so it cannot be styled bare without one leaking into another;
-<code>.field</code> is the one of the three with no distinguishing attribute, so it is
-the one that keeps a class. Hint text is a native <code><small></code>.</p>
-
-<figure class="example">
-<figcaption>Field</figcaption>
-<div>
-<label class="field" style="max-width: 20rem;">
- Name
- <input type="text" placeholder="Call Mom" />
- <small>First line becomes the display name.</small>
-</label>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><label class="field" style="max-width: 20rem;">
- Name
- <input type="text" placeholder="Call Mom" />
- <small>First line becomes the display name.</small>
-</label></code></pre>
-</details>
-</figure>
-
-<h2 id="holding-any-control">Holding any control</h2>
-
-<p>Field wraps <a href="https://kejadlen.github.io/arbitrary-definitions-design-system/components/input/">Input</a>,
-<a href="https://kejadlen.github.io/arbitrary-definitions-design-system/components/select/">Select</a>, or anything else — it
-only owns the caption and the hint line, never the control’s own styling.</p>
-
-<figure class="example">
-<figcaption>Field with a select</figcaption>
-<div>
-<label class="field" style="max-width: 20rem;">
- Unit
- <select>
- <option>Day</option>
- <option selected="">Week</option>
- <option>Month</option>
- <option>Year</option>
- </select>
-</label>
-</div>
-<details><summary>Markup</summary>
-<pre><code><label class="field" style="max-width: 20rem;">
- Unit
- <select>
- <option>Day</option>
- <option selected="">Week</option>
- <option>Month</option>
- <option>Year</option>
- </select>
-</label></code></pre>
-</details>
-</figure>
-
-<h2 id="in-a-row">In a row</h2>
-
-<p><code>.form-row</code> is a sanctioned class for the one shape here with no element of
-its own — a row grouping two fields side by side.</p>
-
-<figure class="example">
-<figcaption>Two fields in a row</figcaption>
-<div>
-<form style="max-width: none;">
- <div class="form-row">
- <label class="field">
- Every
- <input type="number" placeholder="2" />
- </label>
- <label class="field">
- Unit
- <select>
- <option>Day</option><option selected="">Week</option><option>Month</option>
- </select>
- </label>
- </div>
-</form>
-</div>
-<details><summary>Markup</summary>
-<pre><code><form style="max-width: none;">
- <div class="form-row">
- <label class="field">
- Every
- <input type="number" placeholder="2" />
- </label>
- <label class="field">
- Unit
- <select>
- <option>Day</option><option selected="">Week</option><option>Month</option>
- </select>
- </label>
- </div>
-</form></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>label.field</code></td><td></td><td>Required base. Wraps the caption text and the control together.</td></tr>
- <tr><td><code>> small</code></td><td>string</td><td>The hint. Renders below the control.</td></tr>
- <tr><td><code>> small[role="alert"]</code></td><td>string</td><td>An error instead of a hint — see <a href="https://kejadlen.github.io/arbitrary-definitions-design-system/components/input/">Input</a>.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/icon-button.html b/design-bundle/components/icon-button.html
deleted file mode 100644
index dda31e2..0000000
--- a/design-bundle/components/icon-button.html
+++ /dev/null
@@ -1,1840 +0,0 @@
-<!-- @dsCard group="Core" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>IconButton</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>IconButton</h1>
-</header>
-<p class="ad-lead">A square icon-only button. Always pass a label — it becomes the accessible name and the native tooltip, since there is no visible text to fall back on.</p>
-<h2 id="variants">Variants</h2>
-
-<p><code>ghost</code> is the default and transparent. <code>outline</code> is a bordered surface, for
-an icon button sitting alone rather than in a toolbar. <code>accent</code> is a soft
-accent tint, for a toggled or active state — the segmented-tabs pattern this
-system does not otherwise reach for.</p>
-
-<p>A square icon-only button is still a <code><button></code>, but there is no attribute
-that tells it apart from a plain <a href="https://kejadlen.github.io/arbitrary-definitions-design-system/components/button/">Button</a>
-sitting alone — <code>variant</code>/<code>size</code> mean different things for each — so
-<code>.icon-button</code> is the one class this component needs.</p>
-
-<figure class="example">
-<figcaption>Variants</figcaption>
-<div>
-<button class="icon-button" aria-label="Delete">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13" /></svg>
-</button>
-<button class="icon-button" data-variant="outline" aria-label="Settings">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3" /><path d="M12 2.5v3M12 18.5v3M3.6 7.2l2.6 1.5M17.8 15.3l2.6 1.5M3.6 16.8l2.6-1.5M17.8 8.7l2.6-1.5" /></svg>
-</button>
-<button class="icon-button" data-variant="accent" aria-label="Filter (active)">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5h16l-6 8v5l-4 2v-7z" /></svg>
-</button>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><button class="icon-button" aria-label="Delete">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13" /></svg>
-</button>
-<button class="icon-button" data-variant="outline" aria-label="Settings">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3" /><path d="M12 2.5v3M12 18.5v3M3.6 7.2l2.6 1.5M17.8 15.3l2.6 1.5M3.6 16.8l2.6-1.5M17.8 8.7l2.6-1.5" /></svg>
-</button>
-<button class="icon-button" data-variant="accent" aria-label="Filter (active)">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5h16l-6 8v5l-4 2v-7z" /></svg>
-</button></code></pre>
-</details>
-</figure>
-
-<h2 id="sizes">Sizes</h2>
-
-<figure class="example">
-<figcaption>Sizes</figcaption>
-<div>
-<button class="icon-button" data-variant="outline" data-size="sm" aria-label="Back"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6" /></svg></button>
-<button class="icon-button" data-variant="outline" aria-label="Back"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6" /></svg></button>
-<button class="icon-button" data-variant="outline" data-size="lg" aria-label="Back"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6" /></svg></button>
-</div>
-<details><summary>Markup</summary>
-<pre><code><button class="icon-button" data-variant="outline" data-size="sm" aria-label="Back"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6" /></svg></button>
-<button class="icon-button" data-variant="outline" aria-label="Back"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6" /></svg></button>
-<button class="icon-button" data-variant="outline" data-size="lg" aria-label="Back"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6" /></svg></button></code></pre>
-</details>
-</figure>
-
-<h2 id="paired-with-tooltip">Paired with Tooltip</h2>
-
-<p>An icon-only control almost always wants a <a href="https://kejadlen.github.io/arbitrary-definitions-design-system/components/tooltip/">Tooltip</a> too — the <code>aria-label</code> covers accessibility, the tooltip covers a sighted mouse user glancing for a hint.</p>
-
-<figure class="example">
-<figcaption>With a tooltip</figcaption>
-<div>
-<span>
- <button class="icon-button" aria-label="Delete" aria-describedby="icon-btn-tip">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13" /></svg>
- </button>
- <span role="tooltip" id="icon-btn-tip">Delete</span>
-</span>
-</div>
-<details><summary>Markup</summary>
-<pre><code><span>
- <button class="icon-button" aria-label="Delete" aria-describedby="icon-btn-tip">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13" /></svg>
- </button>
- <span role="tooltip" id="icon-btn-tip">Delete</span>
-</span></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>button.icon-button</code></td><td></td><td>Required base — the one class in this component, since nothing distinguishes it from Button structurally.</td></tr>
- <tr><td><code>aria-label</code></td><td>string</td><td>Required — becomes the accessible name and the native tooltip.</td></tr>
- <tr><td><code>data-size</code></td><td><code>sm | lg</code></td><td>28 / 40px square. Omit for the default 34px.</td></tr>
- <tr><td><code>data-variant</code></td><td><code>outline | accent</code></td><td>Omit for the default, transparent ghost look.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/input.html b/design-bundle/components/input.html
deleted file mode 100644
index cfa85fb..0000000
--- a/design-bundle/components/input.html
+++ /dev/null
@@ -1,1817 +0,0 @@
-<!-- @dsCard group="Forms" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Input</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Input</h1>
-</header>
-<p class="ad-lead">A bordered text input, styled to match Select exactly. Usually wrapped in Field for its label and hint.</p>
-<h2 id="basic">Basic</h2>
-
-<p><code><input></code> is the component — styled bare, no class. Nothing else on this
-site uses a text input, so there is nothing for the selector to clash with.</p>
-
-<figure class="example">
-<figcaption>Input</figcaption>
-<div>
-<input type="text" placeholder="Dishwasher manual" style="max-width: 20rem;" />
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><input type="text" placeholder="Dishwasher manual" style="max-width: 20rem;" /></code></pre>
-</details>
-</figure>
-
-<h2 id="focus-and-disabled">Focus and disabled</h2>
-
-<figure class="example">
-<figcaption>States</figcaption>
-<div data-layout="stack">
-<input type="text" value="Focused" style="max-width: 20rem; border-color: var(--ad-color-accent); box-shadow: 0 0 0 2px var(--ad-color-accent-soft);" />
-<input type="text" value="Disabled" disabled="" style="max-width: 20rem;" />
-</div>
-<details><summary>Markup</summary>
-<pre><code><input type="text" value="Focused" style="max-width: 20rem; border-color: var(--ad-color-accent); box-shadow: 0 0 0 2px var(--ad-color-accent-soft);" />
-<input type="text" value="Disabled" disabled="" style="max-width: 20rem;" /></code></pre>
-</details>
-</figure>
-
-<h2 id="invalid">Invalid</h2>
-
-<p>Invalid state is expressed on the control itself, so it works with native
-form validation, plus an error line below. <code>role="alert"</code> is a real
-live-region role for validation text, so it doubles as the selector that
-turns a <code><small></code> hint red.</p>
-
-<figure class="example">
-<figcaption>Invalid</figcaption>
-<div>
-<label class="field" style="max-width: 20rem;">
- Accent hex
- <input type="text" value="not-a-color" aria-invalid="true" />
- <small role="alert">Not a valid hex color.</small>
-</label>
-</div>
-<details><summary>Markup</summary>
-<pre><code><label class="field" style="max-width: 20rem;">
- Accent hex
- <input type="text" value="not-a-color" aria-invalid="true" />
- <small role="alert">Not a valid hex color.</small>
-</label></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>input</code></td><td></td><td>Required base — no class.</td></tr>
- <tr><td><code>type</code></td><td>string</td><td>Any native input type except <code>checkbox</code>/<code>radio</code>, which are their own components.</td></tr>
- <tr><td><code>placeholder</code></td><td>string</td><td></td></tr>
- <tr><td><code>disabled</code></td><td>boolean</td><td></td></tr>
- <tr><td><code>aria-invalid</code></td><td><code>"true"</code></td><td>Reddens the border and fill.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/radio.html b/design-bundle/components/radio.html
deleted file mode 100644
index 1f7a554..0000000
--- a/design-bundle/components/radio.html
+++ /dev/null
@@ -1,1828 +0,0 @@
-<!-- @dsCard group="Forms" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Radio</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Radio</h1>
-</header>
-<p class="ad-lead">Native radio, the same accent-color treatment as Checkbox.</p>
-<h2 id="basic">Basic</h2>
-
-<figure class="example">
-<figcaption>Radio</figcaption>
-<div>
-<label>
- <input type="radio" name="demo-radio-1" checked="" />
- Weekly
-</label>
-<label>
- <input type="radio" name="demo-radio-1" />
- Monthly
-</label>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><label>
- <input type="radio" name="demo-radio-1" checked="" />
- Weekly
-</label>
-<label>
- <input type="radio" name="demo-radio-1" />
- Monthly
-</label></code></pre>
-</details>
-</figure>
-
-<h2 id="as-a-group">As a group</h2>
-
-<figure class="example">
-<figcaption>Interval</figcaption>
-<div>
-<fieldset>
- <legend>Repeat</legend>
- <label>
- <input type="radio" name="demo-radio-2" checked="" />
- Every week
- </label>
- <label>
- <input type="radio" name="demo-radio-2" />
- Every month
- </label>
- <label>
- <input type="radio" name="demo-radio-2" />
- Every year
- </label>
-</fieldset>
-</div>
-<details><summary>Markup</summary>
-<pre><code><fieldset>
- <legend>Repeat</legend>
- <label>
- <input type="radio" name="demo-radio-2" checked="" />
- Every week
- </label>
- <label>
- <input type="radio" name="demo-radio-2" />
- Every month
- </label>
- <label>
- <input type="radio" name="demo-radio-2" />
- Every year
- </label>
-</fieldset></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>input[type="radio"]</code></td><td></td><td>Required base — no class. Tinted with <code>accent-color</code>.</td></tr>
- <tr><td><code>checked</code></td><td>boolean</td><td></td></tr>
- <tr><td><code>name</code></td><td>string</td><td>Groups mutually exclusive radios.</td></tr>
- <tr><td><code>label</code></td><td>text content</td><td>Wrap the input directly — <code>label:has(> input[type="radio"])</code> is what applies the row layout.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/select.html b/design-bundle/components/select.html
deleted file mode 100644
index e4efce9..0000000
--- a/design-bundle/components/select.html
+++ /dev/null
@@ -1,1806 +0,0 @@
-<!-- @dsCard group="Forms" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Select</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Select</h1>
-</header>
-<p class="ad-lead">Native select, styled to match Input exactly.</p>
-<h2 id="basic">Basic</h2>
-
-<p><code><select></code> is the component — styled bare, no class.</p>
-
-<figure class="example">
-<figcaption>Select</figcaption>
-<div>
-<select style="max-width: 20rem;">
- <option>Day</option>
- <option selected="">Week</option>
- <option>Month</option>
- <option>Year</option>
-</select>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><select style="max-width: 20rem;">
- <option>Day</option>
- <option selected="">Week</option>
- <option>Month</option>
- <option>Year</option>
-</select></code></pre>
-</details>
-</figure>
-
-<h2 id="disabled">Disabled</h2>
-
-<figure class="example">
-<figcaption>Disabled</figcaption>
-<div>
-<select disabled="" style="max-width: 20rem;"><option>Week</option></select>
-</div>
-<details><summary>Markup</summary>
-<pre><code><select disabled="" style="max-width: 20rem;"><option>Week</option></select></code></pre>
-</details>
-</figure>
-
-<div class="ad-callout">
- <p style="margin:0; font-size: var(--ad-step--1);">
- The chevron is the one place in this component set that cannot reach a
- <code>var(--ad-*)</code> token — a data-URI <code>background-image</code>
- cannot reference a custom property, so its stroke is a literal hex, kept
- close to <code>--ad-color-text-secondary</code> and commented in the source.
- </p>
-</div>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>select</code></td><td></td><td>Required base — no class.</td></tr>
- <tr><td><code>option</code></td><td></td><td></td></tr>
- <tr><td><code>disabled</code></td><td>boolean</td><td></td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/switch.html b/design-bundle/components/switch.html
deleted file mode 100644
index 9c91dc2..0000000
--- a/design-bundle/components/switch.html
+++ /dev/null
@@ -1,1821 +0,0 @@
-<!-- @dsCard group="Forms" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Switch</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Switch</h1>
-</header>
-<p class="ad-lead">Toggle switch for on/off settings. The one moving part in this system — everything else transitions color or border, never position.</p>
-<h2 id="basic">Basic</h2>
-
-<p><code>role="switch"</code> is the correct ARIA role for a toggle, so it doubles as the
-attribute that tells Switch’s <code>input[type="checkbox"]</code> apart from a plain
-Checkbox — real accessibility markup doing double duty as a style hook. The
-track and thumb still need <code>.switch</code>, one sanctioned fallback class: the
-thumb’s independent position and transition need a second element, more than
-<code>appearance: none</code> plus pseudo-elements on the input itself can cleanly
-carry.</p>
-
-<figure class="example">
-<figcaption>Switch</figcaption>
-<div>
-<label class="switch">
- <input type="checkbox" role="switch" checked="" />
- <span></span>
- Dark mode
-</label>
-<label class="switch">
- <input type="checkbox" role="switch" />
- <span></span>
- Weekly digest
-</label>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><label class="switch">
- <input type="checkbox" role="switch" checked="" />
- <span></span>
- Dark mode
-</label>
-<label class="switch">
- <input type="checkbox" role="switch" />
- <span></span>
- Weekly digest
-</label></code></pre>
-</details>
-</figure>
-
-<h2 id="disabled">Disabled</h2>
-
-<figure class="example">
-<figcaption>Disabled</figcaption>
-<div>
-<label class="switch">
- <input type="checkbox" role="switch" checked="" disabled="" />
- <span></span>
- Always on for this plan
-</label>
-</div>
-<details><summary>Markup</summary>
-<pre><code><label class="switch">
- <input type="checkbox" role="switch" checked="" disabled="" />
- <span></span>
- Always on for this plan
-</label></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>label.switch</code></td><td></td><td>Required wrapper.</td></tr>
- <tr><td><code>input[type="checkbox"][role="switch"]</code></td><td></td><td>Required — the role is what makes it a Switch instead of a Checkbox.</td></tr>
- <tr><td><code>> span</code></td><td></td><td>Required — the track and thumb. No class, just structural position.</td></tr>
- <tr><td><code>checked</code></td><td>boolean</td><td></td></tr>
- <tr><td><code>disabled</code></td><td>boolean</td><td></td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/tabs.html b/design-bundle/components/tabs.html
deleted file mode 100644
index 1b2a5ca..0000000
--- a/design-bundle/components/tabs.html
+++ /dev/null
@@ -1,1848 +0,0 @@
-<!-- @dsCard group="Navigation" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Tabs</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Tabs</h1>
-</header>
-<p class="ad-lead">Two real variants: underline for primary section navigation, segmented for filters. The WAI-ARIA tabs pattern, wired up in vanilla JavaScript — arrows move, Home/End jump to the ends.</p>
-<p>Tabs follows the real WAI-ARIA tabs pattern: <code>[role="tablist"]</code> contains
-<code>[role="tab"]</code> buttons controlling <code>[role="tabpanel"]</code>s. Those roles are
-required for the pattern to be accessible in the first place, so they are the
-entire styling contract too — no classes anywhere in this component. The
-keyboard wiring (<code>assets/js/system.js</code>) only looks for <code>[data-tabs]</code> /
-<code>[role=tab]</code>, so the root wrapper keeps that one data attribute and needs
-nothing else.</p>
-
-<h2 id="underline">Underline</h2>
-
-<p>Mono, with an accent underline. For primary section navigation — a project’s
-own tabs, never a filter. This is the default; no <code>data-variant</code> needed.</p>
-
-<figure class="example">
-<figcaption>Underline</figcaption>
-<div data-layout="stack">
-<div data-tabs="">
- <div role="tablist" aria-label="Repository">
- <button role="tab" id="tabs-code-tab" aria-controls="tabs-code-panel" aria-selected="true" tabindex="0">Code</button>
- <button role="tab" id="tabs-ci-tab" aria-controls="tabs-ci-panel" aria-selected="false" tabindex="-1">CI</button>
- <button role="tab" id="tabs-issues-tab" aria-controls="tabs-issues-panel" aria-selected="false" tabindex="-1">Issues</button>
- </div>
- <div role="tabpanel" id="tabs-code-panel" aria-labelledby="tabs-code-tab" tabindex="0">Repository contents.</div>
- <div role="tabpanel" id="tabs-ci-panel" aria-labelledby="tabs-ci-tab" tabindex="0" hidden="">Build history.</div>
- <div role="tabpanel" id="tabs-issues-panel" aria-labelledby="tabs-issues-tab" tabindex="0" hidden="">Open issues.</div>
-</div>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><div data-tabs="">
- <div role="tablist" aria-label="Repository">
- <button role="tab" id="tabs-code-tab" aria-controls="tabs-code-panel" aria-selected="true" tabindex="0">Code</button>
- <button role="tab" id="tabs-ci-tab" aria-controls="tabs-ci-panel" aria-selected="false" tabindex="-1">CI</button>
- <button role="tab" id="tabs-issues-tab" aria-controls="tabs-issues-panel" aria-selected="false" tabindex="-1">Issues</button>
- </div>
- <div role="tabpanel" id="tabs-code-panel" aria-labelledby="tabs-code-tab" tabindex="0">Repository contents.</div>
- <div role="tabpanel" id="tabs-ci-panel" aria-labelledby="tabs-ci-tab" tabindex="0" hidden="">Build history.</div>
- <div role="tabpanel" id="tabs-issues-panel" aria-labelledby="tabs-issues-tab" tabindex="0" hidden="">Open issues.</div>
-</div></code></pre>
-</details>
-</figure>
-
-<h2 id="segmented">Segmented</h2>
-
-<p>A pill track; the active segment lifts to the surface. For filters — <em>All ·
-Overdue · Upcoming</em> — never primary navigation. <code>data-variant="segmented"</code> on
-the tablist is the only attribute either variant needs, since neither has a
-natural one of its own.</p>
-
-<figure class="example">
-<figcaption>Segmented</figcaption>
-<div data-layout="stack">
-<div data-tabs="">
- <div role="tablist" data-variant="segmented" aria-label="Filter">
- <button role="tab" id="tabs-all-tab" aria-controls="tabs-all-panel" aria-selected="true" tabindex="0">All</button>
- <button role="tab" id="tabs-overdue-tab" aria-controls="tabs-overdue-panel" aria-selected="false" tabindex="-1">Overdue</button>
- <button role="tab" id="tabs-upcoming-tab" aria-controls="tabs-upcoming-panel" aria-selected="false" tabindex="-1">Upcoming</button>
- </div>
- <div role="tabpanel" id="tabs-all-panel" aria-labelledby="tabs-all-tab" tabindex="0">7 series.</div>
- <div role="tabpanel" id="tabs-overdue-panel" aria-labelledby="tabs-overdue-tab" tabindex="0" hidden="">2 series.</div>
- <div role="tabpanel" id="tabs-upcoming-panel" aria-labelledby="tabs-upcoming-tab" tabindex="0" hidden="">5 series.</div>
-</div>
-</div>
-<details><summary>Markup</summary>
-<pre><code><div data-tabs="">
- <div role="tablist" data-variant="segmented" aria-label="Filter">
- <button role="tab" id="tabs-all-tab" aria-controls="tabs-all-panel" aria-selected="true" tabindex="0">All</button>
- <button role="tab" id="tabs-overdue-tab" aria-controls="tabs-overdue-panel" aria-selected="false" tabindex="-1">Overdue</button>
- <button role="tab" id="tabs-upcoming-tab" aria-controls="tabs-upcoming-panel" aria-selected="false" tabindex="-1">Upcoming</button>
- </div>
- <div role="tabpanel" id="tabs-all-panel" aria-labelledby="tabs-all-tab" tabindex="0">7 series.</div>
- <div role="tabpanel" id="tabs-overdue-panel" aria-labelledby="tabs-overdue-tab" tabindex="0" hidden="">2 series.</div>
- <div role="tabpanel" id="tabs-upcoming-panel" aria-labelledby="tabs-upcoming-tab" tabindex="0" hidden="">5 series.</div>
-</div></code></pre>
-</details>
-</figure>
-
-<h2 id="rules">Rules</h2>
-
-<ul>
- <li><strong>Never both variants in one view.</strong> Underline is for the page’s own
-sections; segmented is for filtering what is already on screen.</li>
- <li><strong>Segmented is not primary navigation.</strong> If it decides which screen the
-reader is on, it should be underline.</li>
-</ul>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>[data-tabs]</code></td><td></td><td>Required on the root wrapper — what the keyboard wiring in <code>system.js</code> looks for.</td></tr>
- <tr><td><code>[role="tablist"]</code></td><td></td><td>Required. Contains the tab buttons.</td></tr>
- <tr><td><code>[role="tab"]</code></td><td></td><td>Required, one per item. <code>aria-selected</code> and <code>tabindex</code> are managed by the JS.</td></tr>
- <tr><td><code>[role="tabpanel"]</code></td><td></td><td>Required, one per item, referenced by the tab's <code>aria-controls</code>.</td></tr>
- <tr><td><code>data-variant</code></td><td><code>segmented</code></td><td>On the tablist. Omit for the default underline look.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/tag.html b/design-bundle/components/tag.html
deleted file mode 100644
index dc4dee4..0000000
--- a/design-bundle/components/tag.html
+++ /dev/null
@@ -1,1805 +0,0 @@
-<!-- @dsCard group="Core" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Tag</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Tag</h1>
-</header>
-<p class="ad-lead">A removable mono chip for freeform tags — locations, categories. `[data-dashed]` renders an "add tag" affordance instead of a value.</p>
-<h2 id="default-and-removable">Default and removable</h2>
-
-<p>Same reasoning as Badge: a <code><span></code> is too generic to select bare, so Tag
-keeps one class. The remove control is a real <code><button></code>, styled through the
-descendant selector <code>.tag button</code> — no class of its own.</p>
-
-<figure class="example">
-<figcaption>Tags</figcaption>
-<div>
-<span class="tag">location:garage</span>
-<span class="tag">category:appliance</span>
-<span class="tag">
- category:receipt
- <button aria-label="Remove tag">×</button>
-</span>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><span class="tag">location:garage</span>
-<span class="tag">category:appliance</span>
-<span class="tag">
- category:receipt
- <button aria-label="Remove tag">×</button>
-</span></code></pre>
-</details>
-</figure>
-
-<h2 id="dashed--the-add-tag-affordance">Dashed — the “add tag” affordance</h2>
-
-<figure class="example">
-<figcaption>Add tag</figcaption>
-<div>
-<div class="tag-set">
- <span class="tag">location:garage</span>
- <span class="tag" data-dashed="">+ add tag</span>
-</div>
-</div>
-<details><summary>Markup</summary>
-<pre><code><div class="tag-set">
- <span class="tag">location:garage</span>
- <span class="tag" data-dashed>+ add tag</span>
-</div></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>span.tag</code></td><td></td><td>Required base.</td></tr>
- <tr><td><code>button</code></td><td></td><td>Nest a real <code><button aria-label="Remove tag"></code> to render the × affordance — styled via <code>.tag button</code>, no class needed.</td></tr>
- <tr><td><code>data-dashed</code></td><td>boolean</td><td>Renders an "add tag" affordance instead of a value.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/toast.html b/design-bundle/components/toast.html
deleted file mode 100644
index ac1e35c..0000000
--- a/design-bundle/components/toast.html
+++ /dev/null
@@ -1,1809 +0,0 @@
-<!-- @dsCard group="Feedback" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Toast</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Toast</h1>
-</header>
-<p class="ad-lead">A fixed bottom-right flash bar — the real pattern used for delete confirmations. Auto-dismisses after roughly 8 seconds in practice; wire that timer into the consuming app.</p>
-<h2 id="basic">Basic</h2>
-
-<p><code>role="status"</code> is the correct live-region role for a transient status
-message, so it doubles as the entire styling hook — no base class. The
-example below stays in document flow so it does not cover the page;
-<code>[data-fixed]</code> is what actually pins it bottom-right in a real app. The
-action and dismiss buttons are plain <code><button></code>s told apart by
-<code>aria-label="Dismiss"</code>, an attribute the icon-only close control needs
-anyway.</p>
-
-<figure class="example">
-<figcaption>Toast</figcaption>
-<div>
-<div role="status">
- <span>Deleted "Call Mom"</span>
- <button>Undo</button>
- <button aria-label="Dismiss">×</button>
-</div>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><div role="status">
- <span>Deleted "Call Mom"</span>
- <button>Undo</button>
- <button aria-label="Dismiss">×</button>
-</div></code></pre>
-</details>
-</figure>
-
-<h2 id="without-an-action">Without an action</h2>
-
-<figure class="example">
-<figcaption>No action</figcaption>
-<div>
-<div role="status">
- <span>Series created</span>
- <button aria-label="Dismiss">×</button>
-</div>
-</div>
-<details><summary>Markup</summary>
-<pre><code><div role="status">
- <span>Series created</span>
- <button aria-label="Dismiss">×</button>
-</div></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>[role="status"]</code></td><td></td><td>Required base, on a <code><div></code>.</td></tr>
- <tr><td><code>> span</code></td><td>string</td><td>The message. Required.</td></tr>
- <tr><td><code>> button</code></td><td></td><td>Renders a destructive-colored action, typically "Undo".</td></tr>
- <tr><td><code>> button[aria-label="Dismiss"]</code></td><td></td><td>The × control — the label is what tells it apart from the action button.</td></tr>
- <tr><td><code>data-fixed</code></td><td>boolean</td><td>Pins the toast bottom-right of the viewport. Omit to stay in document flow.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/components/tooltip.html b/design-bundle/components/tooltip.html
deleted file mode 100644
index a87954e..0000000
--- a/design-bundle/components/tooltip.html
+++ /dev/null
@@ -1,1812 +0,0 @@
-<!-- @dsCard group="Feedback" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Tooltip</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Components</span>
- <h1>Tooltip</h1>
-</header>
-<p class="ad-lead">Dark mono tooltip on hover, positioned above the child. Pure CSS — shown on hover and keyboard focus, no JavaScript required.</p>
-<h2 id="basic">Basic</h2>
-
-<p><code>role="tooltip"</code> is the correct ARIA role for the bubble itself, so it
-doubles as the styling hook — no class on the bubble. The wrapping <code><span></code>
-has no attribute of its own, but it does not need one: <code>:has()</code> selects “a
-span that contains a <code>[role=tooltip]</code> bubble” precisely, so the wrapper stays
-bare too. Pair the trigger’s <code>aria-describedby</code> with the bubble’s <code>id</code> so the
-tooltip is announced, not just shown.</p>
-
-<p>Hover or tab to the button below.</p>
-
-<figure class="example">
-<figcaption>Tooltip</figcaption>
-<div>
-<span>
- <button class="icon-button" aria-label="Delete" aria-describedby="tooltip-basic">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13" /></svg>
- </button>
- <span role="tooltip" id="tooltip-basic">Delete</span>
-</span>
-</div>
-<details open=""><summary>Markup</summary>
-<pre><code><span>
- <button class="icon-button" aria-label="Delete" aria-describedby="tooltip-basic">
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13" /></svg>
- </button>
- <span role="tooltip" id="tooltip-basic">Delete</span>
-</span></code></pre>
-</details>
-</figure>
-
-<h2 id="on-any-element">On any element</h2>
-
-<p>A Tooltip wraps whatever it labels — most often an <a href="https://kejadlen.github.io/arbitrary-definitions-design-system/components/icon-button/">IconButton</a>, since that is the control with no visible text of its own.</p>
-
-<figure class="example">
-<figcaption>On a badge</figcaption>
-<div>
-<span>
- <span class="badge" data-tone="danger" tabindex="0" aria-describedby="tooltip-badge">3d overdue</span>
- <span role="tooltip" id="tooltip-badge">Due Tuesday, was Saturday</span>
-</span>
-</div>
-<details><summary>Markup</summary>
-<pre><code><span>
- <span class="badge" data-tone="danger" tabindex="0" aria-describedby="tooltip-badge">3d overdue</span>
- <span role="tooltip" id="tooltip-badge">Due Tuesday, was Saturday</span>
-</span></code></pre>
-</details>
-</figure>
-
-<h2 id="api">API</h2>
-
-<table>
- <thead><tr><th scope="col">Element / attribute</th><th scope="col">Values</th><th scope="col">Notes</th></tr></thead>
- <tbody>
- <tr><td><code>span</code></td><td></td><td>Required wrapper around the trigger and the bubble. Bare — matched structurally via <code>:has()</code>, no class.</td></tr>
- <tr><td><code>[role="tooltip"]</code></td><td>string content</td><td>Required — the bubble. Give it an <code>id</code>.</td></tr>
- <tr><td><code>aria-describedby</code></td><td>the bubble's <code>id</code></td><td>Put it on the trigger element, which needs a real accessible name of its own — a tooltip is not one.</td></tr>
- </tbody>
-</table>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/css/style.css b/design-bundle/css/style.css
deleted file mode 100644
index b3f3073..0000000
--- a/design-bundle/css/style.css
+++ /dev/null
@@ -1,1459 +0,0 @@
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
diff --git a/design-bundle/css/tokens.css b/design-bundle/css/tokens.css
deleted file mode 100644
index 34ff530..0000000
--- a/design-bundle/css/tokens.css
+++ /dev/null
@@ -1,134 +0,0 @@
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
diff --git a/design-bundle/foundations/color.html b/design-bundle/foundations/color.html
deleted file mode 100644
index 56cf6c1..0000000
--- a/design-bundle/foundations/color.html
+++ /dev/null
@@ -1,2399 +0,0 @@
-<!-- @dsCard group="Foundations" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Color</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Foundations</span>
- <h1>Color</h1>
-</header>
-<p class="ad-lead">Two neutral ramps, five accents, two fixed semantic colors, seventeen semantic aliases. Low-chroma warm-gray, never stark white or black.</p>
-<h2 id="the-two-layers">The two layers</h2>
-
-<p>The system separates <em>what a color is</em> from <em>what a color is for</em>.</p>
-
-<p>The <strong>ramps</strong> below are raw material: ten steps of neutral (light), the same
-ten inverted for dark mode, and five accent hues. No component references
-them directly.</p>
-
-<p>The <strong>aliases</strong> underneath are the working vocabulary — <code>--ad-color-text-primary</code>,
-<code>--ad-color-surface-card</code>, <code>--ad-color-accent</code>. Every component stylesheet
-reads from these. Retheming, or switching to dark, means repointing aliases
-at different values — which is exactly what the dark block does.</p>
-
-<div class="ad-callout">
- <p style="margin:0; font-size: var(--ad-step--1);">
- The neutral ramps were authored in <code>oklch()</code> by the three
- projects this system was synthesized from (see
- <a href="https://kejadlen.github.io/arbitrary-definitions-design-system/rationale/">Why arbitrary</a>). Every
- value below is that same color converted to flat sRGB hex — not
- re-picked, not rounded. The contrast figures on this page are computed
- from those hex values with the standard WCAG 2.1 relative-luminance
- formula, then transcribed here as fact rather than typed by eye.
- </p>
-</div>
-
-<h2 id="neutral">Neutral</h2>
-
-<p>Low-chroma warm-gray — the intersection of ketchup’s plain grays, quire’s
-warm cream/dark palette, and domus’s warm paper. Ten steps, not twelve or
-sixteen: the source defines exactly these.</p>
-
-<p class="ad-muted">Low-chroma warm-gray — the intersection of ketchup's plain grays, quire's warm cream/dark palette, and domus's warm paper. Not stark white or black, and not any one project's specific warmth. Ten steps, not twelve: the source defines exactly 0/50/100/150/200/300/500/600/800/900 — steps 400 and 700 do not exist.</p>
-<ul class="ad-swatch-grid">
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #faf9f7; color: #171512;">n-0</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#faf9f7</span>
- <span class="ad-swatch__ratio">1.05 on white</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #fdfdfb; color: #171512;">n-50</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#fdfdfb</span>
- <span class="ad-swatch__ratio">1.02 on white</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #f1f0ed; color: #171512;">n-100</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#f1f0ed</span>
- <span class="ad-swatch__ratio">1.14 on white</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #e8e6e2; color: #171512;">n-150</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#e8e6e2</span>
- <span class="ad-swatch__ratio">1.25 on white</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #dcdad7; color: #171512;">n-200</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#dcdad7</span>
- <span class="ad-swatch__ratio">1.40 on white</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #c0bdb9; color: #171512;">n-300</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#c0bdb9</span>
- <span class="ad-swatch__ratio">1.87 on white</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #888681; color: #171512;">n-500</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#888681</span>
- <span class="ad-swatch__ratio">3.64 on white</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #5f5d59; color: #ffffff;">n-600</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#5f5d59</span>
- <span class="ad-swatch__ratio">6.57 on white</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #2a2926; color: #ffffff;">n-800</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#2a2926</span>
- <span class="ad-swatch__ratio">14.55 on white</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #100f0d; color: #ffffff;">n-900</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#100f0d</span>
- <span class="ad-swatch__ratio">19.16 on white</span>
- </div>
- </li>
-</ul>
-
-<p class="ad-muted">The same low-chroma warm-gray scale, inverted, matching quire's OS-preference dark palette. Same ten step numbers as `neutral`; `0` is the darkest step here (the dark-theme page background) rather than the lightest.</p>
-<ul class="ad-swatch-grid">
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #0e0d0b; color: #ffffff;">nd-0</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#0e0d0b</span>
- <span class="ad-swatch__ratio">1.08 on black</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #151412; color: #ffffff;">nd-50</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#151412</span>
- <span class="ad-swatch__ratio">1.14 on black</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #1e1d1a; color: #ffffff;">nd-100</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#1e1d1a</span>
- <span class="ad-swatch__ratio">1.25 on black</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #252421; color: #ffffff;">nd-150</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#252421</span>
- <span class="ad-swatch__ratio">1.35 on black</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #2c2b29; color: #ffffff;">nd-200</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#2c2b29</span>
- <span class="ad-swatch__ratio">1.48 on black</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #44423f; color: #ffffff;">nd-300</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#44423f</span>
- <span class="ad-swatch__ratio">2.10 on black</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #7c7a76; color: #ffffff;">nd-500</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#7c7a76</span>
- <span class="ad-swatch__ratio">4.90 on black</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #a09e9a; color: #171512;">nd-600</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#a09e9a</span>
- <span class="ad-swatch__ratio">7.85 on black</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #d9d7d4; color: #171512;">nd-800</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#d9d7d4</span>
- <span class="ad-swatch__ratio">14.62 on black</span>
- </div>
- </li>
- <li class="ad-swatch">
- <div class="ad-swatch__chip" style="background: #e9e8e6; color: #171512;">nd-900</div>
- <div class="ad-swatch__meta">
- <span class="ad-swatch__hex">#e9e8e6</span>
- <span class="ad-swatch__ratio">17.15 on black</span>
- </div>
- </li>
-</ul>
-
-<h2 id="accent">Accent</h2>
-
-<p>One swappable accent per project — never two in the same view. Signal Teal is
-the default; the other four are the sanctioned menu a project can switch to.</p>
-
-<ul class="ad-accent-grid">
- <li>
- <div class="ad-accent-demo" style="background: #3a6a63;">teal (default)</div>
- <div class="ad-specimen__meta"><code>#3a6a63</code><span>6.14:1 on white</span></div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">Default. Neutral, technical.</p>
- </li>
- <li>
- <div class="ad-accent-demo" style="background: #9a5a3c;">clay</div>
- <div class="ad-specimen__meta"><code>#9a5a3c</code><span>5.38:1 on white</span></div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">Warm, archival — domus's flavor.</p>
- </li>
- <li>
- <div class="ad-accent-demo" style="background: #2b4a78;">ink-blue</div>
- <div class="ad-specimen__meta"><code>#2b4a78</code><span>8.92:1 on white</span></div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">Sober, utilitarian.</p>
- </li>
- <li>
- <div class="ad-accent-demo" style="background: #93701f;">ochre</div>
- <div class="ad-specimen__meta"><code>#93701f</code><span>4.59:1 on white</span></div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">Dry, papery.</p>
- </li>
- <li>
- <div class="ad-accent-demo" style="background: #6a3a5c;">plum</div>
- <div class="ad-specimen__meta"><code>#6a3a5c</code><span>8.85:1 on white</span></div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">Quiet, personal.</p>
- </li>
-</ul>
-
-<div class="ad-callout">
- <p style="margin:0; font-size: var(--ad-step--1);">
- All five clear AA (4.5:1) for white text at their own value, but Ochre is
- the tightest of the five at roughly 4.6:1 — closer to the floor than the
- others (Ink Blue and Plum both clear 8.5:1). That is a real property of a
- dry, papery ochre and is not being rounded away; a project choosing Ochre
- as its accent should re-check any place it sets small white text directly
- on the accent fill, rather than through <code>--ad-color-accent-fg</code>
- on a full-size Button.
- </p>
-</div>
-
-<h2 id="semantic-aliases">Semantic aliases</h2>
-
-<p>Both themes, side by side. The left half of each chip is the light value and
-the right half is the dark one.</p>
-
-<h3 id="surfaces">Surfaces</h3>
-
-<p class="ad-muted">Backgrounds, from the page itself up to a card sitting on it.</p>
-
-<table>
- <thead>
- <tr>
- <th scope="col">Token</th>
- <th scope="col">Light</th>
- <th scope="col">Dark</th>
- <th scope="col">Use for</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #faf9f7"></span>
- <span style="background: #0e0d0b"></span>
- </span>
- <code>--ad-color-surface-page</code>
- </div>
- </td>
- <td><code>neutral.0</code></td>
- <td><code>neutral_dark.0</code></td>
- <td>The page itself. Nothing sits behind it.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #fdfdfb"></span>
- <span style="background: #151412"></span>
- </span>
- <code>--ad-color-surface-card</code>
- </div>
- </td>
- <td><code>neutral.50</code></td>
- <td><code>neutral_dark.50</code></td>
- <td>Cards, dialogs, toasts — anything that reads as a sheet on the page.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #f1f0ed"></span>
- <span style="background: #1e1d1a"></span>
- </span>
- <code>--ad-color-surface-fill</code>
- </div>
- </td>
- <td><code>neutral.100</code></td>
- <td><code>neutral_dark.100</code></td>
- <td>Recessed fill — a hovered row, a segmented-tab track, a photo placeholder.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #e8e6e2"></span>
- <span style="background: #252421"></span>
- </span>
- <code>--ad-color-surface-fill-2</code>
- </div>
- </td>
- <td><code>neutral.150</code></td>
- <td><code>neutral_dark.150</code></td>
- <td>A second, deeper fill step — the diagonal-grain stripe inside an empty photo slot.</td>
- </tr>
- </tbody>
- </table>
-
-<h3 id="borders">Borders</h3>
-
-<p class="ad-muted">Two weights. Hairlines do most of the elevation work in this system, so there was never a reason for a third.</p>
-
-<table>
- <thead>
- <tr>
- <th scope="col">Token</th>
- <th scope="col">Light</th>
- <th scope="col">Dark</th>
- <th scope="col">Use for</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #dcdad7"></span>
- <span style="background: #2c2b29"></span>
- </span>
- <code>--ad-color-border-hairline</code>
- </div>
- </td>
- <td><code>neutral.200</code></td>
- <td><code>neutral_dark.200</code></td>
- <td>Card edges, row dividers, dialog dividers. The default edge everywhere.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #c0bdb9"></span>
- <span style="background: #44423f"></span>
- </span>
- <code>--ad-color-border-default</code>
- </div>
- </td>
- <td><code>neutral.300</code></td>
- <td><code>neutral_dark.300</code></td>
- <td>Input and button borders — anything a reader has to recognize as a control.</td>
- </tr>
- </tbody>
- </table>
-
-<h3 id="text">Text</h3>
-
-<p class="ad-muted">Three levels of emphasis, deliberately not four. Past three, a reader stops perceiving a hierarchy and starts perceiving noise.</p>
-
-<table>
- <thead>
- <tr>
- <th scope="col">Token</th>
- <th scope="col">Light</th>
- <th scope="col">Dark</th>
- <th scope="col">Use for</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #100f0d"></span>
- <span style="background: #e9e8e6"></span>
- </span>
- <code>--ad-color-text-primary</code>
- </div>
- </td>
- <td><code>neutral.900</code></td>
- <td><code>neutral_dark.900</code></td>
- <td>Body copy, headings, and every control label.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #5f5d59"></span>
- <span style="background: #a09e9a"></span>
- </span>
- <code>--ad-color-text-secondary</code>
- </div>
- </td>
- <td><code>neutral.600</code></td>
- <td><code>neutral_dark.600</code></td>
- <td>Supporting copy, hints, mono meta values, type-label's color.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #888681"></span>
- <span style="background: #7c7a76"></span>
- </span>
- <code>--ad-color-text-tertiary</code>
- </div>
- </td>
- <td><code>neutral.500</code></td>
- <td><code>neutral_dark.500</code></td>
- <td>Placeholders and de-emphasized metadata only — never body text. This step is intentionally sub-AA against the page; see the caveat on the Color page.</td>
- </tr>
- </tbody>
- </table>
-
-<h3 id="accent-1">Accent</h3>
-
-<p class="ad-muted">One swappable accent per project, held constant across a whole view. `-ink` and `-soft` re-derive from `--ad-color-accent` via `color-mix()` exactly as the source computes them, so retheming the accent retones both automatically.</p>
-
-<table>
- <thead>
- <tr>
- <th scope="col">Token</th>
- <th scope="col">Light</th>
- <th scope="col">Dark</th>
- <th scope="col">Use for</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #3a6a63"></span>
- <span style="background: #3a6a63"></span>
- </span>
- <code>--ad-color-accent</code>
- </div>
- </td>
- <td><code>accent.teal</code></td>
- <td><code>accent.teal</code></td>
- <td>Primary buttons, links, focus affordance, the active tab underline. Never two accents in one view.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #ffffff"></span>
- <span style="background: #ffffff"></span>
- </span>
- <code>--ad-color-accent-fg</code>
- </div>
- </td>
- <td><code>#ffffff</code></td>
- <td><code>#ffffff</code></td>
- <td>Label and icon color on a filled accent surface. Fixed white, not a ramp reference.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip" aria-hidden="true" style="background: repeating-linear-gradient(45deg, var(--ad-color-surface-fill) 0 4px, var(--ad-color-surface-card) 4px 8px);"></span>
- <code>--ad-color-accent-ink</code>
- </div>
- </td>
- <td><code>color-mix(in oklch, var(--ad-color-accent) 78%, black)</code></td>
- <td><code>color-mix(in oklch, var(--ad-color-accent) 78%, black)</code></td>
- <td>Text sitting on an `-soft` accent tint — an IconButton's active state, an accent avatar's initials.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip" aria-hidden="true" style="background: repeating-linear-gradient(45deg, var(--ad-color-surface-fill) 0 4px, var(--ad-color-surface-card) 4px 8px);"></span>
- <code>--ad-color-accent-soft</code>
- </div>
- </td>
- <td><code>color-mix(in oklch, var(--ad-color-accent) 12%, white)</code></td>
- <td><code>color-mix(in oklch, var(--ad-color-accent) 12%, white)</code></td>
- <td>The tint behind an accent Badge, a toggled IconButton, an accent avatar chip.</td>
- </tr>
- </tbody>
- </table>
-
-<h3 id="status">Status</h3>
-
-<p class="ad-muted">Exactly two states, both fixed — they read the same in every project and are never swapped the way the accent is.</p>
-
-<table>
- <thead>
- <tr>
- <th scope="col">Token</th>
- <th scope="col">Light</th>
- <th scope="col">Dark</th>
- <th scope="col">Use for</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #3f7a4a"></span>
- <span style="background: #3f7a4a"></span>
- </span>
- <code>--ad-color-success</code>
- </div>
- </td>
- <td><code>#3f7a4a</code></td>
- <td><code>#3f7a4a</code></td>
- <td>Success text and icons — a completed task's check, a saved-state badge.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip" aria-hidden="true" style="background: repeating-linear-gradient(45deg, var(--ad-color-surface-fill) 0 4px, var(--ad-color-surface-card) 4px 8px);"></span>
- <code>--ad-color-success-bg</code>
- </div>
- </td>
- <td><code>color-mix(in oklch, var(--ad-color-success) 12%, white)</code></td>
- <td><code>color-mix(in oklch, var(--ad-color-success) 12%, white)</code></td>
- <td>Tint behind a success Badge. Mixed against literal white, so it stays constant across themes.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip ad-alias-chip--pair" aria-hidden="true">
- <span style="background: #ad3a2c"></span>
- <span style="background: #ad3a2c"></span>
- </span>
- <code>--ad-color-danger</code>
- </div>
- </td>
- <td><code>#ad3a2c</code></td>
- <td><code>#ad3a2c</code></td>
- <td>Overdue/destructive text, the Toast undo action, a danger Button's fill.</td>
- </tr>
- <tr>
- <td>
- <div class="ad-alias-row">
- <span class="ad-alias-chip" aria-hidden="true" style="background: repeating-linear-gradient(45deg, var(--ad-color-surface-fill) 0 4px, var(--ad-color-surface-card) 4px 8px);"></span>
- <code>--ad-color-danger-bg</code>
- </div>
- </td>
- <td><code>color-mix(in oklch, var(--ad-color-danger) 10%, white)</code></td>
- <td><code>color-mix(in oklch, var(--ad-color-danger) 10%, white)</code></td>
- <td>Tint behind a danger Badge. Mixed against literal white, so it stays constant across themes.</td>
- </tr>
- </tbody>
- </table>
-
-<h2 id="contrast-that-has-to-hold">Contrast that has to hold</h2>
-
-<p>Color is the one part of this system that is not arbitrary: a ratio is a
-fact about two colors and a pair of eyes, and it does not care what the
-palette wants. The pairings below are fixed facts about the token values
-above, computed once with the standard WCAG 2.1 relative-luminance formula
-and checked by hand rather than by a build-time test.</p>
-
-<h3 id="text--451-minimum">Text — 4.5:1 minimum</h3>
-
-<p class="ad-muted">WCAG 2.1 SC 1.4.3 (normal-size text)</p>
-
-<table>
- <thead>
- <tr>
- <th scope="col">Pairing</th>
- <th scope="col">Where it shows up</th>
- <th scope="col" class="num">Light</th>
- <th scope="col" class="num">Dark</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>
- <span class="ad-alias-row">
- <span class="ad-alias-chip" aria-hidden="true" style="background: #faf9f7; color: #100f0d; display: grid; place-items: center; font-size: 10px;">Aa</span>
- <code>color-text-primary<br /><span class="ad-subtle">on color-surface-page</span></code>
- </span>
- </td>
- <td>Body copy</td>
- <td class="num">18.21</td>
- <td class="num">15.86</td>
- </tr>
- <tr>
- <td>
- <span class="ad-alias-row">
- <span class="ad-alias-chip" aria-hidden="true" style="background: #faf9f7; color: #5f5d59; display: grid; place-items: center; font-size: 10px;">Aa</span>
- <code>color-text-secondary<br /><span class="ad-subtle">on color-surface-page</span></code>
- </span>
- </td>
- <td>Supporting copy</td>
- <td class="num">6.24</td>
- <td class="num">7.26</td>
- </tr>
- <tr>
- <td>
- <span class="ad-alias-row">
- <span class="ad-alias-chip" aria-hidden="true" style="background: #3a6a63; color: #ffffff; display: grid; place-items: center; font-size: 10px;">Aa</span>
- <code>color-accent-fg<br /><span class="ad-subtle">on color-accent</span></code>
- </span>
- </td>
- <td>The label on a primary or dark-variant Button.</td>
- <td class="num">6.14</td>
- <td class="num">6.14</td>
- </tr>
- <tr>
- <td>
- <span class="ad-alias-row">
- <span class="ad-alias-chip" aria-hidden="true" style="background: #ffffff; color: #3f7a4a; display: grid; place-items: center; font-size: 10px;">Aa</span>
- <code>color-success<br /><span class="ad-subtle">on color-accent-fg</span></code>
- </span>
- </td>
- <td>Success text on a light backdrop — proxied by color-accent-fg</td>
- <td class="num">5.13</td>
- <td class="num">5.13</td>
- </tr>
- <tr>
- <td>
- <span class="ad-alias-row">
- <span class="ad-alias-chip" aria-hidden="true" style="background: #ffffff; color: #ad3a2c; display: grid; place-items: center; font-size: 10px;">Aa</span>
- <code>color-danger<br /><span class="ad-subtle">on color-accent-fg</span></code>
- </span>
- </td>
- <td>Overdue/destructive text on a light backdrop</td>
- <td class="num">6.14</td>
- <td class="num">6.14</td>
- </tr>
- </tbody>
- </table>
-
-<div class="ad-callout">
- <p style="margin:0; font-size: var(--ad-step--1);">
- Two things this contract deliberately does not assert.
- <strong>Text tertiary</strong> — <code>--ad-color-text-tertiary</code>
- (neutral.500) is roughly 3.46:1 against the page in light mode, under the
- 4.5:1 floor. The source documents that step as muted-faint text —
- placeholders and de-emphasized metadata, never body copy — so this is a
- real, intentional property of the palette, not a bug to patch by
- darkening the step.
- <strong>Borders</strong> — <code>--ad-color-border-hairline</code> and
- <code>--ad-color-border-default</code> sit well under the 3:1 that WCAG
- 1.4.11 asks of a meaningful boundary. The source's own words are
- "hairline (1px) borders and dividers do most of the elevation work" —
- borders here are deliberately quiet, and the source never claims a 3:1
- bar for them, so this contract does not invent one.
- </p>
-</div>
-
-<h2 id="rules">Rules</h2>
-
-<ul>
- <li><strong>Never write a hex outside <code>assets/css/tokens.css</code>.</strong> If a component
-needs a color that does not exist yet, add the alias.</li>
- <li><strong>One accent per project, never two in a view.</strong> Swapping <code>--ad-color-accent</code>
-re-derives <code>-ink</code> and <code>-soft</code> automatically via <code>color-mix()</code>.</li>
- <li><strong><code>--ad-color-success</code> and <code>--ad-color-danger</code> are fixed.</strong> They read the
-same in every project and are never swapped the way the accent is.</li>
-</ul>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/foundations/elevation.html b/design-bundle/foundations/elevation.html
deleted file mode 100644
index 670422e..0000000
--- a/design-bundle/foundations/elevation.html
+++ /dev/null
@@ -1,1821 +0,0 @@
-<!-- @dsCard group="Foundations" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Elevation</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Foundations</span>
- <h1>Elevation</h1>
-</header>
-<p class="ad-lead">Two shadow levels only. Hairline (1px) borders do most of the elevation work in this system; shadow is reserved for the one floating layer in a view.</p>
-<h2 id="borders-do-the-work">Borders do the work</h2>
-
-<p>The source’s own rule: “hairline (1px) borders and dividers do most of the
-elevation work”. A flat, bordered <a href="https://kejadlen.github.io/arbitrary-definitions-design-system/components/card/">Card</a>
-is the default everywhere. Shadow is the exception, not the baseline.</p>
-
-<h2 id="the-two-levels">The two levels</h2>
-
-<ul class="ad-elevation-grid">
- <li>
- <div class="ad-elevation-demo" style="box-shadow: 0 1px 2px rgba(20, 18, 14, 0.05);"></div>
- <div class="ad-specimen__meta"><code>shadow-sm</code></div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">Barely-there separation — a Switch thumb, a focused Input.</p>
- </li>
- <li>
- <div class="ad-elevation-demo" style="box-shadow: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);"></div>
- <div class="ad-specimen__meta"><code>shadow-float</code></div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">The one floating layer in a view. Apply it to at most one element on screen at a time.</p>
- </li>
-</ul>
-
-<figure class="example">
-<figcaption>Flat vs. float</figcaption>
-<div data-layout="grid" data-surface="sunken">
-<article class="card">
- <div class="card-body">
- <h3 style="margin:0; font: 600 var(--ad-step--1)/1.3 var(--ad-font-sans);">Flat</h3>
- <p style="margin:0; color: var(--ad-color-text-secondary); font-size: var(--ad-step--1);">The default. A hairline border, no shadow.</p>
- </div>
-</article>
-<article class="card" data-elevated="">
- <div class="card-body">
- <h3 style="margin:0; font: 600 var(--ad-step--1)/1.3 var(--ad-font-sans);">Elevated</h3>
- <p style="margin:0; color: var(--ad-color-text-secondary); font-size: var(--ad-step--1);">shadow-float. Reserved for one element per view — a Dialog, a Toast.</p>
- </div>
-</article>
-</div>
-<details><summary>Markup</summary>
-<pre><code><article class="card">
- <div class="card-body">
- <h3>Flat</h3>
- <p>The default. A hairline border, no shadow.</p>
- </div>
-</article>
-<article class="card" data-elevated>
- <div class="card-body">
- <h3>Elevated</h3>
- <p>shadow-float. Reserved for one element per view — a Dialog, a Toast.</p>
- </div>
-</article></code></pre>
-</details>
-</figure>
-
-<h2 id="elevation-in-the-dark-theme">Elevation in the dark theme</h2>
-
-<p>Shadows barely register on a near-black surface. The dark theme leans on
-surface lightness instead — <code>--ad-color-surface-card</code> is one neutral step
-lighter than <code>--ad-color-surface-page</code>, same as in light mode. The shadow
-tokens still apply; they simply stop being the primary signal.</p>
-
-<h2 id="rules">Rules</h2>
-
-<ul>
- <li><strong>At most one <code>--ad-shadow-float</code> on screen.</strong> If two things both claim to
-be the topmost layer, neither is.</li>
- <li><strong>Border or shadow, not both, for a given surface’s edge.</strong> A card that
-both borders and floats looks like a sticker.</li>
- <li><strong>Never animate a shadow’s blur.</strong> If a floated element needs to arrive,
-animate its <code>opacity</code>, or do not animate it at all.</li>
-</ul>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/foundations/motion.html b/design-bundle/foundations/motion.html
deleted file mode 100644
index 059eb4b..0000000
--- a/design-bundle/foundations/motion.html
+++ /dev/null
@@ -1,1843 +0,0 @@
-<!-- @dsCard group="Foundations" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Motion</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Foundations</span>
- <h1>Motion</h1>
-</header>
-<p class="ad-lead">Two durations, one easing curve, and one rule that overrides both: if the reader asked for less motion, they get none. This is an interface, not a title sequence.</p>
-<h2 id="durations">Durations</h2>
-
-<p>Short ease transitions on hover and focus only — no bounce, no springy
-easing, no page-transition choreography.</p>
-
-<table>
- <thead><tr><th scope="col">Token</th><th scope="col">Value</th><th scope="col">Use for</th></tr></thead>
- <tbody>
- <tr>
- <td><code>--ad-dur-fast</code></td>
- <td><code>0.12s</code></td>
- <td>Hover and focus color/border transitions — the default.</td>
- </tr>
- <tr>
- <td><code>--ad-dur-base</code></td>
- <td><code>0.16s</code></td>
- <td>Switch track and thumb — the one moving part in the system.</td>
- </tr>
- </tbody>
- </table>
-
-<h2 id="one-easing">One easing</h2>
-
-<p>There is exactly one curve in the system. Hover the tile below to run it.</p>
-
-<ul class="ad-motion-grid">
- <li>
- <div class="ad-motion-demo" tabindex="0">
- <span class="ad-motion-demo__dot"></span>
- </div>
- <div class="ad-specimen__meta"><code>--ad-ease</code></div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">The only easing curve in the system. Fast out, settles gently, applied to every transition.</p>
- </li>
-</ul>
-
-<h2 id="reduced-motion-is-not-a-downgrade">Reduced motion is not a downgrade</h2>
-
-<p><code>tokens.css</code> includes a <code>prefers-reduced-motion: reduce</code> block that sets
-every duration token to <code>0ms</code>, and the base stylesheet clamps any remaining
-transition or animation to a hundredth of a millisecond. Components do not
-have to opt in, and cannot opt out.</p>
-
-<pre><code class="language-css">@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-</code></pre>
-
-<p>The state change still happens. The Switch still moves. It simply arrives
-instead of traveling.</p>
-
-<figure class="example">
-<figcaption>Motion in practice</figcaption>
-<div>
-<label class="switch">
- <input type="checkbox" role="switch" checked="" />
- <span></span>
- Dark mode
-</label>
-<label class="switch">
- <input type="checkbox" role="switch" />
- <span></span>
- Weekly digest
-</label>
-</div>
-<details><summary>Markup</summary>
-<pre><code><label class="switch">
- <input type="checkbox" role="switch" checked>
- <span></span>
- Dark mode
-</label>
-<label class="switch">
- <input type="checkbox" role="switch">
- <span></span>
- Weekly digest
-</label></code></pre>
-</details>
-</figure>
-
-<h2 id="rules">Rules</h2>
-
-<ul>
- <li><strong>Transition named properties, never <code>all</code>.</strong> <code>transition: all</code> animates
-things you did not think about, including layout.</li>
- <li><strong>Hover states shift a background one step deeper, never a color or
-opacity trick.</strong> Surface → fill is the whole vocabulary.</li>
- <li><strong>Press is not animated.</strong> Rely on the hover-darken plus native <code>:active</code>,
-if anything at all.</li>
- <li><strong>Motion is for hover and focus only.</strong> No page-transition choreography.</li>
-</ul>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/foundations/space.html b/design-bundle/foundations/space.html
deleted file mode 100644
index 3e4bd50..0000000
--- a/design-bundle/foundations/space.html
+++ /dev/null
@@ -1,1941 +0,0 @@
-<!-- @dsCard group="Foundations" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Space</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Foundations</span>
- <h1>Space</h1>
-</header>
-<p class="ad-lead">Nine fluid Utopia steps, 3xs through 3xl — the same clamp() config as type, because there is no fixed base unit here to count multiples of.</p>
-<h2 id="the-scale">The scale</h2>
-
-<div class="ad-ruler">
- <div class="ad-ruler__row">
- <code>space-3xs</code>
- <span class="ad-ruler__num">5px</span>
- <span class="ad-ruler__bar" style="width: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem); min-width: 1px;"></span>
- </div>
- <div class="ad-ruler__row">
- <code>space-2xs</code>
- <span class="ad-ruler__num">9 → 10px</span>
- <span class="ad-ruler__bar" style="width: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem); min-width: 1px;"></span>
- </div>
- <div class="ad-ruler__row">
- <code>space-xs</code>
- <span class="ad-ruler__num">14 → 15px</span>
- <span class="ad-ruler__bar" style="width: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem); min-width: 1px;"></span>
- </div>
- <div class="ad-ruler__row">
- <code>space-s</code>
- <span class="ad-ruler__num">18 → 20px</span>
- <span class="ad-ruler__bar" style="width: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem); min-width: 1px;"></span>
- </div>
- <div class="ad-ruler__row">
- <code>space-m</code>
- <span class="ad-ruler__num">27 → 30px</span>
- <span class="ad-ruler__bar" style="width: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem); min-width: 1px;"></span>
- </div>
- <div class="ad-ruler__row">
- <code>space-l</code>
- <span class="ad-ruler__num">36 → 40px</span>
- <span class="ad-ruler__bar" style="width: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem); min-width: 1px;"></span>
- </div>
- <div class="ad-ruler__row">
- <code>space-xl</code>
- <span class="ad-ruler__num">54 → 60px</span>
- <span class="ad-ruler__bar" style="width: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem); min-width: 1px;"></span>
- </div>
- <div class="ad-ruler__row">
- <code>space-2xl</code>
- <span class="ad-ruler__num">72 → 80px</span>
- <span class="ad-ruler__bar" style="width: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem); min-width: 1px;"></span>
- </div>
- <div class="ad-ruler__row">
- <code>space-3xl</code>
- <span class="ad-ruler__num">108 → 120px</span>
- <span class="ad-ruler__bar" style="width: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem); min-width: 1px;"></span>
- </div>
-</div>
-
-<h2 id="how-to-pick-one">How to pick one</h2>
-
-<table>
- <thead>
- <tr>
- <th>Distance between</th>
- <th>Reach for</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>An icon and its own label</td>
- <td><code>--ad-space-3xs</code> / <code>--ad-space-2xs</code></td>
- </tr>
- <tr>
- <td>A field’s label and its control</td>
- <td><code>--ad-space-2xs</code></td>
- </tr>
- <tr>
- <td>Two controls in a row, CardRow padding</td>
- <td><code>--ad-space-xs</code></td>
- </tr>
- <tr>
- <td>Two fields in a form, a Dialog’s title/footer padding</td>
- <td><code>--ad-space-s</code></td>
- </tr>
- <tr>
- <td>Card body padding, a Dialog’s body padding</td>
- <td><code>--ad-space-m</code></td>
- </tr>
- <tr>
- <td>Two sections of a page</td>
- <td><code>--ad-space-l</code></td>
- </tr>
- <tr>
- <td>Major section spacing</td>
- <td><code>--ad-space-xl</code> / <code>--ad-space-2xl</code></td>
- </tr>
- <tr>
- <td>Hero and empty-state breathing room</td>
- <td><code>--ad-space-3xl</code></td>
- </tr>
- </tbody>
-</table>
-
-<figure class="example">
-<figcaption>The same card at three densities</figcaption>
-<div data-layout="grid">
-<article class="card">
- <div class="card-body" style="gap: var(--ad-space-3xs); padding: var(--ad-space-xs);">
- <h3 style="margin:0; font: 600 var(--ad-step--1)/1.3 var(--ad-font-sans);">Compact</h3>
- <p style="margin:0; color: var(--ad-color-text-secondary); font-size: var(--ad-step--1);">space-xs padding, space-3xs gap. For dense lists.</p>
- </div>
-</article>
-<article class="card">
- <div class="card-body">
- <h3 style="margin:0; font: 600 var(--ad-step--1)/1.3 var(--ad-font-sans);">Default</h3>
- <p style="margin:0; color: var(--ad-color-text-secondary); font-size: var(--ad-step--1);">space-m padding, space-2xs gap. What Card ships with.</p>
- </div>
-</article>
-<article class="card">
- <div class="card-body" style="gap: var(--ad-space-s); padding: var(--ad-space-l);">
- <h3 style="margin:0; font: 600 var(--ad-step--1)/1.3 var(--ad-font-sans);">Roomy</h3>
- <p style="margin:0; color: var(--ad-color-text-secondary); font-size: var(--ad-step--1);">space-l padding, space-s gap. For a card that is the whole screen.</p>
- </div>
-</article>
-</div>
-<details><summary>Markup</summary>
-<pre><code><article class="card">
- <div class="card-body" style="gap: var(--ad-space-3xs); padding: var(--ad-space-xs);">
- <h3>Compact</h3>
- <p>space-xs padding, space-3xs gap. For dense lists.</p>
- </div>
-</article>
-<article class="card">
- <div class="card-body">
- <h3>Default</h3>
- <p>space-m padding, space-2xs gap. What Card ships with.</p>
- </div>
-</article>
-<article class="card">
- <div class="card-body" style="gap: var(--ad-space-s); padding: var(--ad-space-l);">
- <h3>Roomy</h3>
- <p>space-l padding, space-s gap. For a card that is the whole screen.</p>
- </div>
-</article></code></pre>
-</details>
-</figure>
-
-<h2 id="radius">Radius</h2>
-
-<p>4/6/10px — small and quiet, kept modest so it reads as a neutral default
-rather than any one source project’s specific softness. Nothing pill-shaped
-except true pills.</p>
-
-<ul class="ad-radius-grid">
- <li>
- <div class="ad-radius-demo" style="border-radius: 4px;"></div>
- <div class="ad-specimen__meta">
- <code>radius-sm</code>
- <span>4px</span>
- </div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">Buttons, inputs, badges, tags.</p>
- </li>
- <li>
- <div class="ad-radius-demo" style="border-radius: 6px;"></div>
- <div class="ad-specimen__meta">
- <code>radius-md</code>
- <span>6px</span>
- </div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">IconButton, the segmented-tabs track, avatar chips.</p>
- </li>
- <li>
- <div class="ad-radius-demo" style="border-radius: 10px;"></div>
- <div class="ad-specimen__meta">
- <code>radius-lg</code>
- <span>10px</span>
- </div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">Cards, dialogs, toasts, photo slots — the system's "surface" radius.</p>
- </li>
- <li>
- <div class="ad-radius-demo" style="border-radius: 999px;"></div>
- <div class="ad-specimen__meta">
- <code>radius-full</code>
- <span>999px</span>
- </div>
- <p class="ad-muted" style="font-size: var(--ad-step--2); margin: var(--ad-space-3xs) 0 0;">True pills only — Badge, Tag, Switch, round avatars.</p>
- </li>
-</ul>
-
-<h2 id="rules">Rules</h2>
-
-<ul>
- <li><strong>Space comes from the parent.</strong> A component sets its own internal padding
-and never its external margin; the layout that contains it owns the gap.</li>
- <li><strong>Use <code>gap</code>.</strong> Flex and grid gaps do not collapse and do not need a
-<code>:last-child</code> reset.</li>
- <li><strong>A value not on the scale is a bug</strong>, not a nudge. If a gap looks wrong,
-the scale is wrong and should change for everybody.</li>
-</ul>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/foundations/typography.html b/design-bundle/foundations/typography.html
deleted file mode 100644
index cfa620b..0000000
--- a/design-bundle/foundations/typography.html
+++ /dev/null
@@ -1,1987 +0,0 @@
-<!-- @dsCard group="Foundations" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Typography</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Foundations</span>
- <h1>Typography</h1>
-</header>
-<p class="ad-lead">Three families, eight fluid steps, eight compound styles. Sans for interface, mono for every label and technical value, serif as an opt-in reading variant.</p>
-<h2 id="families">Families</h2>
-
-<div class="ad-specimen">
- <div class="ad-specimen__meta">
- <code>--ad-font-sans</code>
- <span>Interface text — every component, every screen. Web-safe; nothing is loaded for it.</span>
- </div>
- <div class="ad-specimen__sample" style="font-family: var(--ad-font-sans); font-size: 1.5rem;">
- Arbitrary Definitions — 0123456789
- </div>
-</div>
-<div class="ad-specimen">
- <div class="ad-specimen__meta">
- <code>--ad-font-mono</code>
- <span>Every label, meta value, technical/catalog value, and code sample. The system's one loaded webfont.</span>
- </div>
- <div class="ad-specimen__sample" style="font-family: var(--ad-font-mono); font-size: 1.5rem;">
- Arbitrary Definitions — 0123456789
- </div>
-</div>
-<div class="ad-specimen">
- <div class="ad-specimen__meta">
- <code>--ad-font-serif</code>
- <span>Opt-in reading variant for a project that wants an editorial, archival feel (domus-style). Not loaded by default; web-safe only.</span>
- </div>
- <div class="ad-specimen__sample" style="font-family: var(--ad-font-serif); font-size: 1.5rem;">
- Arbitrary Definitions — 0123456789
- </div>
-</div>
-
-<p>Only one webfont is loaded — IBM Plex Mono, at 400/500/600:</p>
-
-<pre><code class="language-css">@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap');
-</code></pre>
-
-<p>Sans is a web-safe system stack; serif is Georgia-based and opt-in, for a
-project that wants an editorial or archival feel. Neither is fetched.</p>
-
-<h2 id="fluid-scale">Fluid scale</h2>
-
-<p>Eight steps, <code>clamp()</code>-based (Utopia, 320→1240px viewport). The body sits at
-<code>--ad-step-0</code> — 18px on a phone, 20px on a wide screen — with no fixed
-breakpoint in between.</p>
-
-<div class="ad-specimen">
- <div class="ad-specimen__meta">
- <code>--ad-step--2</code>
- <span>12.5 → 12.8px</span>
- <span>type-label — eyebrows, catalog labels, meta.</span>
- </div>
- <div class="ad-specimen__sample" style="font-size: var(--ad-step--2);">
- The quick brown fox jumps over the lazy dog
- </div>
-</div>
-<div class="ad-specimen">
- <div class="ad-specimen__meta">
- <code>--ad-step--1</code>
- <span>15 → 16px</span>
- <span>type-body-sm and type-mono — secondary copy, technical values.</span>
- </div>
- <div class="ad-specimen__sample" style="font-size: var(--ad-step--1);">
- The quick brown fox jumps over the lazy dog
- </div>
-</div>
-<div class="ad-specimen">
- <div class="ad-specimen__meta">
- <code>--ad-step-0</code>
- <span>18 → 20px</span>
- <span>type-body — the base size, and the body element's own size.</span>
- </div>
- <div class="ad-specimen__sample" style="font-size: var(--ad-step-0);">
- The quick brown fox jumps over the lazy dog
- </div>
-</div>
-<div class="ad-specimen">
- <div class="ad-specimen__meta">
- <code>--ad-step-1</code>
- <span>22 → 25px</span>
- <span>type-h3 — card and subsection headings.</span>
- </div>
- <div class="ad-specimen__sample" style="font-size: var(--ad-step-1);">
- The quick brown fox jumps over the lazy dog
- </div>
-</div>
-<div class="ad-specimen">
- <div class="ad-specimen__meta">
- <code>--ad-step-2</code>
- <span>26 → 31px</span>
- <span>type-h2 — section headings.</span>
- </div>
- <div class="ad-specimen__sample" style="font-size: var(--ad-step-2);">
- The quick brown fox jumps over the lazy dog
- </div>
-</div>
-<div class="ad-specimen">
- <div class="ad-specimen__meta">
- <code>--ad-step-3</code>
- <span>31 → 39px</span>
- <span>type-h1 — screen titles.</span>
- </div>
- <div class="ad-specimen__sample" style="font-size: var(--ad-step-3);">
- The quick brown fox jumps over the lazy dog
- </div>
-</div>
-<div class="ad-specimen">
- <div class="ad-specimen__meta">
- <code>--ad-step-4</code>
- <span>37 → 49px</span>
- <span>type-display — one hero title per screen, at most.</span>
- </div>
- <div class="ad-specimen__sample" style="font-size: var(--ad-step-4);">
- The quick brown fox jumps over the lazy dog
- </div>
-</div>
-<div class="ad-specimen">
- <div class="ad-specimen__meta">
- <code>--ad-step-5</code>
- <span>45 → 61px</span>
- <span>Reserved headroom. No compound style claims it yet.</span>
- </div>
- <div class="ad-specimen__sample" style="font-size: var(--ad-step-5);">
- The quick brown fox jumps over the lazy dog
- </div>
-</div>
-
-<h2 id="the-eight-compound-styles">The eight compound styles</h2>
-
-<p>Real, specific numbers from the source — not a generic ramp compressed to
-fit. Each class sets family, size, weight, line-height, and (where the
-source specifies one) letter-spacing in a single declaration.</p>
-
-<table>
- <thead><tr><th scope="col">Class</th><th scope="col">Weight</th><th scope="col">Size</th><th scope="col">Line-height</th><th scope="col">Tracking</th><th scope="col">Use for</th></tr></thead>
- <tbody>
- <tr>
- <td><code>.type-display</code></td>
- <td>600</td>
- <td><code>--ad-step-4</code></td>
- <td>1.08</td>
- <td>-0.015em</td>
- <td>Page-level hero title, once per screen.</td>
- </tr>
- <tr>
- <td><code>.type-h1</code></td>
- <td>600</td>
- <td><code>--ad-step-3</code></td>
- <td>1.12</td>
- <td>-0.012em</td>
- <td>Screen title.</td>
- </tr>
- <tr>
- <td><code>.type-h2</code></td>
- <td>600</td>
- <td><code>--ad-step-2</code></td>
- <td>1.16</td>
- <td>-0.01em</td>
- <td>Section heading.</td>
- </tr>
- <tr>
- <td><code>.type-h3</code></td>
- <td>600</td>
- <td><code>--ad-step-1</code></td>
- <td>1.25</td>
- <td>normal</td>
- <td>Card / subsection heading.</td>
- </tr>
- <tr>
- <td><code>.type-body</code></td>
- <td>400</td>
- <td><code>--ad-step-0</code></td>
- <td>1.55</td>
- <td>normal</td>
- <td>Body copy.</td>
- </tr>
- <tr>
- <td><code>.type-body-sm</code></td>
- <td>400</td>
- <td><code>--ad-step--1</code></td>
- <td>1.5</td>
- <td>normal</td>
- <td>Secondary copy, hints.</td>
- </tr>
- <tr>
- <td><code>.type-label</code></td>
- <td>500</td>
- <td><code>--ad-step--2</code></td>
- <td>1</td>
- <td>0.08em</td>
- <td>Eyebrows, catalog labels, meta — SAVED, RECOMMENDED, OVERDUE.</td>
- </tr>
- <tr>
- <td><code>.type-mono</code></td>
- <td>400</td>
- <td><code>--ad-step--1</code></td>
- <td>1.5</td>
- <td>normal</td>
- <td>Technical values, IDs, dates, code.</td>
- </tr>
- </tbody>
- </table>
-
-<figure class="example">
-<figcaption>All eight, in order</figcaption>
-<div data-layout="stack">
-<div class="type-display">Display</div>
-<h1 class="type-h1">Heading one</h1>
-<h2 class="type-h2">Heading two</h2>
-<h3 class="type-h3">Heading three</h3>
-<p class="type-body">Body copy at the base size, 1.55 line-height.</p>
-<p class="type-body-sm">Secondary copy, one step down.</p>
-<span class="type-label">Catalog label</span>
-<span class="type-mono">technical.value / 2026-08-21 / #3a6a63</span>
-</div>
-<details><summary>Markup</summary>
-<pre><code><div class="type-display">Display</div>
-<h1 class="type-h1">Heading one</h1>
-<h2 class="type-h2">Heading two</h2>
-<h3 class="type-h3">Heading three</h3>
-<p class="type-body">Body copy at the base size, 1.55 line-height.</p>
-<p class="type-body-sm">Secondary copy, one step down.</p>
-<span class="type-label">Catalog label</span>
-<span class="type-mono">technical.value / 2026-08-21 / #3a6a63</span></code></pre>
-</details>
-</figure>
-
-<h2 id="rules">Rules</h2>
-
-<ul>
- <li><strong>Three families, and no fourth.</strong> A new typeface needs a reason a weight
-or a size cannot supply.</li>
- <li><strong>Mono is not decoration.</strong> Every label, meta value, ID, date, and code
-sample is mono — it is the one thread present in all three source projects.</li>
- <li><strong><code>type-label</code> is always uppercase, mono, and tracked.</strong> It is the one
-place uppercase belongs in this system.</li>
- <li><strong>Never set a size in <code>px</code>.</strong> The eight steps are fluid on purpose.</li>
-</ul>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/patterns/archive.html b/design-bundle/patterns/archive.html
deleted file mode 100644
index 3ce15b8..0000000
--- a/design-bundle/patterns/archive.html
+++ /dev/null
@@ -1,1860 +0,0 @@
-<!-- @dsCard group="Patterns" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Archive</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Patterns</span>
- <h1>Archive — capture app</h1>
-</header>
-<p class="ad-lead">A capture/document mobile app. Card list, bottom capture dock, photo slots with the diagonal-grain empty state. A generic demonstration of the system, not a recreation of any one source project's actual screens.</p>
-<p>Archive is not a real product — it is the system’s own reference layout for a
-mobile capture flow: the shape <code>kejadlen/domus</code> (a household inventory and
-document archive) would take if it were rebuilt on this token set, at its
-390×760 frame. Three screens, abbreviated to what each one adds.</p>
-
-<figure class="example">
-<figcaption>Home — recent captures</figcaption>
-<div>
-<div style="width: 300px; height: 560px; background: var(--ad-color-surface-page); border-radius: var(--ad-radius-lg); box-shadow: var(--ad-shadow-float); overflow:hidden; display:flex; flex-direction:column; position:relative;">
- <header style="padding: 16px var(--ad-space-m) var(--ad-space-2xs);">
- <span style="font-weight:600; font-size: var(--ad-step-1); letter-spacing:-0.01em;">Archive</span>
- </header>
- <div style="flex:1; overflow:hidden; padding: 0 var(--ad-space-m);">
- <div style="display:flex; align-items:baseline; gap:8px; margin: var(--ad-space-s) 0 var(--ad-space-xs);">
- <span style="font-weight:700; font-size: var(--ad-step-0);">Recent</span>
- <span class="type-label" style="margin-left:auto;">3 tracked</span>
- </div>
- <ul class="card">
- <li>
- <span class="avatar" data-square=""><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 8 12 3 3 8v8l9 5 9-5V8Z" /><path d="M3 8l9 5 9-5M12 13v8" /></svg></span>
- <div style="flex:1; min-width:0;">
- <div style="font-weight:550; font-size: var(--ad-step--1); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">Dishwasher manual</div>
- <div class="type-label" style="margin-top:2px;">PDF · 2.1MB</div>
- </div>
- <span class="type-mono" style="color: var(--ad-color-text-tertiary); font-size: var(--ad-step--2);">2h</span>
- </li>
- <li>
- <span class="avatar" data-square=""><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 8 12 3 3 8v8l9 5 9-5V8Z" /><path d="M3 8l9 5 9-5M12 13v8" /></svg></span>
- <div style="flex:1; min-width:0;">
- <div style="font-weight:550; font-size: var(--ad-step--1);">Sofa receipt</div>
- <div class="type-label" style="margin-top:2px;">JPG · 640KB</div>
- </div>
- <span class="type-mono" style="color: var(--ad-color-text-tertiary); font-size: var(--ad-step--2);">1d</span>
- </li>
- <li>
- <span class="avatar" data-square=""><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 8 12 3 3 8v8l9 5 9-5V8Z" /><path d="M3 8l9 5 9-5M12 13v8" /></svg></span>
- <div style="flex:1; min-width:0;">
- <div style="font-weight:550; font-size: var(--ad-step--1);">Passport scan</div>
- <div class="type-label" style="margin-top:2px;">PDF · 890KB</div>
- </div>
- <span class="type-mono" style="color: var(--ad-color-text-tertiary); font-size: var(--ad-step--2);">4d</span>
- </li>
- </ul>
- </div>
- <div style="position:absolute; left:0; right:0; bottom:0; display:flex; justify-content:center; padding: 14px 20px 22px; background: linear-gradient(to top, var(--ad-color-surface-page) 65%, transparent);">
- <button data-variant="primary" data-size="lg" data-block="">
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 8a2 2 0 0 1 2-2h1.5l1-1.5h9l1 1.5H20a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8Z" /><circle cx="12" cy="13" r="3.5" /></svg>
- Take a photo
- </button>
- </div>
-</div>
-<div style="width: 300px; height: 560px; background: var(--ad-color-surface-page); border-radius: var(--ad-radius-lg); box-shadow: var(--ad-shadow-float); overflow:hidden; display:flex; flex-direction:column;">
- <header style="display:flex; align-items:center; gap:8px; padding: 16px var(--ad-space-m) var(--ad-space-2xs);">
- <button class="icon-button" data-size="sm" aria-label="Back"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6" /></svg></button>
- <span style="font-weight:600; font-size: var(--ad-step-0);">Save</span>
- </header>
- <div style="flex:1; padding: 0 var(--ad-space-m);">
- <div style="height: 180px; border-radius: var(--ad-radius-lg); border: 1px solid var(--ad-color-border-default); background: repeating-linear-gradient(45deg, transparent 0 8px, var(--ad-color-surface-fill-2) 8px 9px), var(--ad-color-surface-fill); display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px; margin-top: var(--ad-space-s);">
- <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 8 12 3 3 8v8l9 5 9-5V8Z" /><path d="M3 8l9 5 9-5M12 13v8" /></svg>
- <span class="type-label">Photo preview</span>
- </div>
- <label class="field" style="margin-top: var(--ad-space-m);">
- Name
- <input placeholder="Dishwasher manual" />
- </label>
- </div>
- <div style="padding: var(--ad-space-m); display:flex; gap: var(--ad-space-2xs);">
- <button style="flex:1;">Retake</button>
- <button data-variant="primary" style="flex:1;">Save</button>
- </div>
-</div>
-<div style="width: 300px; height: 560px; background: var(--ad-color-surface-page); border-radius: var(--ad-radius-lg); box-shadow: var(--ad-shadow-float); overflow:hidden; display:flex; flex-direction:column;">
- <header style="display:flex; align-items:center; gap:8px; padding: 16px var(--ad-space-m) var(--ad-space-2xs);">
- <button class="icon-button" data-size="sm" aria-label="Back"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6" /></svg></button>
- <span class="type-label">Archive</span>
- </header>
- <div style="flex:1; overflow:hidden; padding: 0 var(--ad-space-m) var(--ad-space-l);">
- <h1 style="font-weight:700; font-size: var(--ad-step-2); letter-spacing:-0.01em; margin: var(--ad-space-xs) 0 var(--ad-space-2xs);">Dishwasher manual</h1>
- <div style="display:flex; gap:6px; flex-wrap:wrap; margin-bottom: var(--ad-space-m);">
- <span class="tag">location:kitchen</span>
- <span class="tag" data-dashed="">+ add tag</span>
- </div>
- <div class="type-label" style="margin-bottom: var(--ad-space-2xs);">File</div>
- <ul class="card">
- <li>
- <span class="avatar" data-square=""><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 8 12 3 3 8v8l9 5 9-5V8Z" /><path d="M3 8l9 5 9-5M12 13v8" /></svg></span>
- <div style="flex:1; font-size: var(--ad-step--1);">PDF · 2.1MB</div>
- </li>
- </ul>
- <div class="type-label" style="margin: var(--ad-space-m) 0 var(--ad-space-2xs);">Notes</div>
- <p style="font-size: var(--ad-step--1); color: var(--ad-color-text-secondary); line-height:1.55; margin:0;">No notes yet.</p>
- </div>
-</div>
-</div>
-</figure>
-
-<h2 id="what-this-screen-is-testing">What this screen is testing</h2>
-
-<ul>
- <li><strong>The diagonal-grain empty state.</strong> The only patterned background this
-system permits, used only inside an empty photo slot.</li>
- <li><strong>CardRow as a file row, twice.</strong> The same component holds a scannable
-list on Home and a single, focused row on Detail — no special “detail row”
-variant needed.</li>
- <li><strong>Tag alongside its own dashed “add” affordance.</strong> The two live in one row,
-reading as one continuous, extendable list.</li>
- <li><strong><code>type-label</code> as the workhorse.</strong> File size, tag count, and the back-button
-screen name all reach for the same mono catalog-label convention as Badge.</li>
-</ul>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>
diff --git a/design-bundle/patterns/loop.html b/design-bundle/patterns/loop.html
deleted file mode 100644
index c5f4150..0000000
--- a/design-bundle/patterns/loop.html
+++ /dev/null
@@ -1,1932 +0,0 @@
-<!-- @dsCard group="Patterns" -->
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Loop</title>
-<link rel="preconnect" href="https://fonts.googleapis.com">
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap">
-<style>
-/* Arbitrary Definitions — design tokens. Hand-maintained; edit values directly. */
-
-:root {
- /* Palette ramps — reference only. Components use the aliases below. */
- --ad-neutral-0: #faf9f7;
- --ad-neutral-50: #fdfdfb;
- --ad-neutral-100: #f1f0ed;
- --ad-neutral-150: #e8e6e2;
- --ad-neutral-200: #dcdad7;
- --ad-neutral-300: #c0bdb9;
- --ad-neutral-500: #888681;
- --ad-neutral-600: #5f5d59;
- --ad-neutral-800: #2a2926;
- --ad-neutral-900: #100f0d;
- --ad-neutral-dark-0: #0e0d0b;
- --ad-neutral-dark-50: #151412;
- --ad-neutral-dark-100: #1e1d1a;
- --ad-neutral-dark-150: #252421;
- --ad-neutral-dark-200: #2c2b29;
- --ad-neutral-dark-300: #44423f;
- --ad-neutral-dark-500: #7c7a76;
- --ad-neutral-dark-600: #a09e9a;
- --ad-neutral-dark-800: #d9d7d4;
- --ad-neutral-dark-900: #e9e8e6;
- --ad-accent-teal: #3a6a63;
- --ad-accent-clay: #9a5a3c;
- --ad-accent-ink-blue: #2b4a78;
- --ad-accent-ochre: #93701f;
- --ad-accent-plum: #6a3a5c;
-
- /* Surfaces */
- --ad-color-surface-page: #faf9f7;
- --ad-color-surface-card: #fdfdfb;
- --ad-color-surface-fill: #f1f0ed;
- --ad-color-surface-fill-2: #e8e6e2;
-
- /* Borders */
- --ad-color-border-hairline: #dcdad7;
- --ad-color-border-default: #c0bdb9;
-
- /* Text */
- --ad-color-text-primary: #100f0d;
- --ad-color-text-secondary: #5f5d59;
- --ad-color-text-tertiary: #888681;
-
- /* Accent */
- --ad-color-accent: #3a6a63;
- --ad-color-accent-fg: #ffffff;
- --ad-color-accent-ink: color-mix(in oklch, var(--ad-color-accent) 78%, black);
- --ad-color-accent-soft: color-mix(in oklch, var(--ad-color-accent) 12%, white);
-
- /* Status (fixed — never swapped like the accent) */
- --ad-color-success: #3f7a4a;
- --ad-color-success-bg: color-mix(in oklch, var(--ad-color-success) 12%, white);
- --ad-color-danger: #ad3a2c;
- --ad-color-danger-bg: color-mix(in oklch, var(--ad-color-danger) 10%, white);
-
- /* Type families */
- --ad-font-sans: -apple-system, "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
- --ad-font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, "Courier New", monospace;
- --ad-font-serif: Georgia, "Times New Roman", "Iowan Old Style", serif;
-
- /* Type steps — fluid (Utopia scale), the design system's own body-text size */
- --ad-step--2: clamp(0.7813rem, 0.7736rem + 0.0341vw, 0.8rem);
- --ad-step--1: clamp(0.9375rem, 0.9119rem + 0.1136vw, 1rem);
- --ad-step-0: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-step-1: clamp(1.35rem, 1.2631rem + 0.3864vw, 1.5625rem);
- --ad-step-2: clamp(1.62rem, 1.4837rem + 0.6057vw, 1.9531rem);
- --ad-step-3: clamp(1.944rem, 1.7405rem + 0.9044vw, 2.4414rem);
- --ad-step-4: clamp(2.3328rem, 2.0387rem + 1.3072vw, 3.0518rem);
- --ad-step-5: clamp(2.7994rem, 2.384rem + 1.8461vw, 3.8147rem);
-
- /* Space */
- --ad-space-3xs: clamp(0.3125rem, 0.3125rem + 0vw, 0.3125rem);
- --ad-space-2xs: clamp(0.5625rem, 0.5369rem + 0.1136vw, 0.625rem);
- --ad-space-xs: clamp(0.875rem, 0.8494rem + 0.1136vw, 0.9375rem);
- --ad-space-s: clamp(1.125rem, 1.0739rem + 0.2273vw, 1.25rem);
- --ad-space-m: clamp(1.6875rem, 1.6108rem + 0.3409vw, 1.875rem);
- --ad-space-l: clamp(2.25rem, 2.1477rem + 0.4545vw, 2.5rem);
- --ad-space-xl: clamp(3.375rem, 3.2216rem + 0.6818vw, 3.75rem);
- --ad-space-2xl: clamp(4.5rem, 4.2955rem + 0.9091vw, 5rem);
- --ad-space-3xl: clamp(6.75rem, 6.4432rem + 1.3636vw, 7.5rem);
-
- /* Radius */
- --ad-radius-sm: 4px;
- --ad-radius-md: 6px;
- --ad-radius-lg: 10px;
- --ad-radius-full: 999px;
- --ad-border-w: 1px;
-
- /* Elevation */
- --ad-shadow-sm: 0 1px 2px rgba(20, 18, 14, 0.05);
- --ad-shadow-float: 0 2px 6px rgba(20, 18, 14, 0.06), 0 10px 24px -12px rgba(20, 18, 14, 0.18);
-
- /* Motion */
- --ad-dur-fast: 0.12s;
- --ad-dur-base: 0.16s;
- --ad-ease: cubic-bezier(0.2, 0, 0, 1);
-}
-
-@media (prefers-color-scheme: dark) {
- :root:not([data-theme="light"]) {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
- }
-}
-
-:root[data-theme="dark"] {
- color-scheme: dark;
- --ad-color-surface-page: #0e0d0b;
- --ad-color-surface-card: #151412;
- --ad-color-surface-fill: #1e1d1a;
- --ad-color-surface-fill-2: #252421;
- --ad-color-border-hairline: #2c2b29;
- --ad-color-border-default: #44423f;
- --ad-color-text-primary: #e9e8e6;
- --ad-color-text-secondary: #a09e9a;
- --ad-color-text-tertiary: #7c7a76;
-}
-
-@media (prefers-reduced-motion: reduce) {
- :root {
- --ad-dur-fast: 0ms;
- --ad-dur-base: 0ms;
- }
-}
-
-/* A short reset. Everything it sets is something the system would otherwise
- have to override in every component.
-
- The rem values used for this documentation site's own chrome (measure,
- content width, sidebar width, header height) belong to this site, not to
- the design system it documents — the source design system defines no
- container-width tokens at all, so there is nothing under `--ad-*` to reach
- for here. See the header comment in site/shell.css. */
-
-*,
-*::before,
-*::after { box-sizing: border-box; }
-
-html {
- -webkit-text-size-adjust: 100%;
- scroll-behavior: smooth;
- scroll-padding-top: calc(3.5rem + var(--ad-space-s));
-}
-
-@media (prefers-reduced-motion: reduce) {
- html { scroll-behavior: auto; }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
- }
-}
-
-body {
- margin: 0;
- background: var(--ad-color-surface-page);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- line-height: 1.55;
- font-synthesis-weight: none;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
-}
-
-::selection {
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
-}
-
-h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }
-ul[class], ol[class] { list-style: none; margin: 0; padding: 0; }
-
-img, svg, video { display: block; max-width: 100%; height: auto; }
-
-button, input, select, textarea {
- font: inherit;
- color: inherit;
-}
-
-hr {
- height: 1px;
- margin: var(--ad-space-l) 0;
- border: 0;
- background: var(--ad-color-border-hairline);
-}
-
-/* One focus ring, defined once. No component is allowed its own. */
-:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
- border-radius: var(--ad-radius-sm);
-}
-:focus:not(:focus-visible) { outline: none; }
-
-[hidden] { display: none !important; }
-
-.ad-visually-hidden {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip-path: inset(50%);
- white-space: nowrap;
- border: 0;
-}
-
-/* Every rule here reads a type token for family and size. Weight, line-height,
- and letter-spacing are hardcoded to the exact numbers the source ships —
- there is no `--ad-weight-*` / `--ad-leading-*` / `--ad-tracking-*` scale in
- the real system, only eight fixed compound styles (see the Typography
- foundation page, which this file implements verbatim). */
-
-.type-display { font: 600 var(--ad-step-4)/1.08 var(--ad-font-sans); letter-spacing: -0.015em; }
-.type-h1, h1 { font: 600 var(--ad-step-3)/1.12 var(--ad-font-sans); letter-spacing: -0.012em; }
-.type-h2, h2 { font: 600 var(--ad-step-2)/1.16 var(--ad-font-sans); letter-spacing: -0.01em; }
-.type-h3, h3 { font: 600 var(--ad-step-1)/1.25 var(--ad-font-sans); }
-.type-body { font: 400 var(--ad-step-0)/1.55 var(--ad-font-sans); }
-.type-body-sm { font: 400 var(--ad-step--1)/1.5 var(--ad-font-sans); }
-.type-label {
- font: 500 var(--ad-step--2)/1 var(--ad-font-mono);
- text-transform: uppercase;
- letter-spacing: 0.08em;
- color: var(--ad-color-text-secondary);
-}
-.type-mono { font: 400 var(--ad-step--1)/1.5 var(--ad-font-mono); }
-
-/* Prose defaults for the documentation body copy. These read the same
- tokens the compound classes above do; they are not a second scale. */
-h1, h2, h3, h4 { font-weight: 600; text-wrap: balance; }
-
-h4 { font: 600 var(--ad-step-0)/1.3 var(--ad-font-sans); }
-
-p, ul, ol { margin: 0 0 var(--ad-space-s); }
-li + li { margin-top: var(--ad-space-3xs); }
-
-a {
- color: var(--ad-color-accent);
- text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
- text-underline-offset: 0.18em;
- text-decoration-thickness: 1px;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- text-decoration-color var(--ad-dur-fast) var(--ad-ease);
-}
-a:hover {
- color: var(--ad-color-accent-ink);
- text-decoration-color: currentColor;
-}
-
-strong, b { font-weight: 600; }
-
-small { font-size: var(--ad-step--1); }
-
-.ad-lead {
- font-size: var(--ad-step-1);
- line-height: 1.5;
- color: var(--ad-color-text-secondary);
- max-width: 68ch;
- text-wrap: pretty;
-}
-
-.ad-muted { color: var(--ad-color-text-secondary); }
-.ad-subtle { color: var(--ad-color-text-tertiary); }
-
-code, kbd, samp, pre {
- font-family: var(--ad-font-mono);
- font-feature-settings: "liga" 0;
-}
-
-:not(pre) > code {
- padding: 0.15em 0.4em;
- font-size: 0.875em;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-sm);
- white-space: nowrap;
-}
-
-kbd {
- display: inline-block;
- padding: 0.1em 0.45em;
- font-size: var(--ad-step--2);
- line-height: 1.6;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-bottom-width: 2px;
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-secondary);
-}
-
-blockquote {
- margin-block: var(--ad-space-s);
- padding-left: var(--ad-space-s);
- border-left: 2px solid var(--ad-color-accent);
- color: var(--ad-color-text-secondary);
-}
-
-/* Button
- A flat, quiet button that recedes rather than performs — no gradients, no
- shine. Variants: default, primary, dark, ghost, danger. Sizes: sm, md
- (default), lg — padding and font step only, weight and radius stay put.
-
- The contract is the element itself: a bare <button> is styled directly, no
- class required. An <a> that acts like a button (navigates rather than
- changes something — see the Button page's "Links that act like buttons")
- opts in with a single `.btn` class, since a bare `a` selector would catch
- every ordinary prose link on the site. `:not(.icon-button)` keeps this
- block from leaking onto IconButton, which shares the <button> tag but is
- an entirely different shape. */
-
-button:not(.icon-button),
-a.btn {
- --_bg: var(--ad-color-surface-card);
- --_fg: var(--ad-color-text-primary);
- --_border: var(--ad-color-border-default);
- --_pad: var(--ad-space-xs) var(--ad-space-s);
- --_font: var(--ad-step--1);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: var(--ad-space-2xs);
- padding: var(--_pad);
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-sans);
- font-size: var(--_font);
- font-weight: 550;
- letter-spacing: -0.01em;
- line-height: 1.2;
- text-align: center;
- text-decoration: none;
- white-space: nowrap;
- cursor: pointer;
- transition: filter var(--ad-dur-fast) var(--ad-ease),
- border-color var(--ad-dur-fast) var(--ad-ease);
-}
-
-:is(button:not(.icon-button), a.btn):hover:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.96); }
-:is(button:not(.icon-button), a.btn):active:not(:disabled):not([aria-disabled="true"]) { filter: brightness(0.92); }
-
-button:not(.icon-button):disabled,
-:is(button:not(.icon-button), a.btn)[aria-disabled="true"] {
- opacity: 0.5;
- cursor: default;
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="primary"] {
- --_bg: var(--ad-color-accent);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-accent);
-}
-
-/* Reserved for the single most-committing action in a view — a final Save,
- never a whole row of them. */
-:is(button:not(.icon-button), a.btn)[data-variant="dark"] {
- --_bg: var(--ad-color-text-primary);
- --_fg: var(--ad-color-surface-page);
- --_border: var(--ad-color-text-primary);
-}
-
-:is(button:not(.icon-button), a.btn)[data-variant="ghost"] {
- --_bg: transparent;
- --_fg: var(--ad-color-text-primary);
- --_border: transparent;
-}
-
-/* The source hardcodes this label white rather than deriving it — danger
- is not "on a filled accent surface", so --ad-color-accent-fg is reused
- here only because its resolved value is the same literal white, not
- because the two roles are the same thing. */
-:is(button:not(.icon-button), a.btn)[data-variant="danger"] {
- --_bg: var(--ad-color-danger);
- --_fg: var(--ad-color-accent-fg);
- --_border: var(--ad-color-danger);
-}
-
-:is(button:not(.icon-button), a.btn)[data-size="sm"] { --_pad: 0.375rem 0.75rem; --_font: 0.8125rem; }
-:is(button:not(.icon-button), a.btn)[data-size="lg"] { --_pad: 0.75rem 1.375rem; --_font: var(--ad-step-0); }
-
-:is(button:not(.icon-button), a.btn)[data-block] { width: 100%; }
-
-/* Button group — [role="group"] is already the correct ARIA role for a
- toolbar of related buttons, so it doubles as the styling hook for free. */
-[role="group"] {
- display: inline-flex;
- isolation: isolate;
-}
-[role="group"] > button { border-radius: 0; }
-[role="group"] > button:first-child { border-start-start-radius: var(--ad-radius-md); border-end-start-radius: var(--ad-radius-md); }
-[role="group"] > button:last-child { border-start-end-radius: var(--ad-radius-md); border-end-end-radius: var(--ad-radius-md); }
-[role="group"] > button + button { margin-inline-start: -1px; }
-[role="group"] > button:hover,
-[role="group"] > button:focus-visible { z-index: 1; }
-
-/* IconButton — a square icon-only button. Always needs an aria-label; it
- becomes both the accessible name and the native tooltip. There is no
- attribute that distinguishes "a button that is only an icon" from a plain
- Button, so this is the one sanctioned class in this file. */
-.icon-button {
- --_size: 2.125rem;
- --_bg: transparent;
- --_border: transparent;
- --_fg: var(--ad-color-text-secondary);
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- padding: 0;
- flex: none;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-md);
- background: var(--_bg);
- color: var(--_fg);
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease),
- color var(--ad-dur-fast) var(--ad-ease);
-}
-.icon-button:hover:not(:disabled) { background: var(--ad-color-surface-fill-2); }
-.icon-button:disabled { opacity: 0.5; cursor: default; }
-
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
-
-.icon-button[data-variant="outline"] { --_bg: var(--ad-color-surface-card); --_border: var(--ad-color-border-default); --_fg: var(--ad-color-text-primary); }
-.icon-button[data-variant="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); }
-
-/* Field
- The labeled field wrapper — a <label> that wraps its own caption text
- together with the control, so the association is native and needs no
- `for`/`id` pair. The caption is mono, uppercase, tracked — the same
- catalog-label convention as Badge and type-label.
-
- A <label> is reused for three different shapes across this system (this
- wrapper, Checkbox/Radio's row, Switch's row), so it cannot be styled bare
- without one shape leaking into another. Field is the one of the three with
- no distinguishing attribute of its own, so it gets the sanctioned class;
- Checkbox/Radio tell themselves apart structurally instead (see below). */
-.field {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- min-width: 0;
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Hint and error read the native fine-print element. `role="alert"` is a
- real live-region role for validation text, so it doubles as the selector
- that turns a hint red. */
-.field > small {
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-.field > small[role="alert"] { color: var(--ad-color-danger); }
-
-/* Input / Select — bordered, matched to each other exactly. Both tags ARE
- the component, so they are styled bare; nothing else on this site uses a
- text input or a select. */
-input:not([type="checkbox"]):not([type="radio"]),
-select {
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- text-transform: none;
- letter-spacing: normal;
- font-weight: 400;
- outline: none;
- transition: border-color var(--ad-dur-fast) var(--ad-ease),
- box-shadow var(--ad-dur-fast) var(--ad-ease);
-}
-input::placeholder { color: var(--ad-color-text-tertiary); }
-
-input:not([type="checkbox"]):not([type="radio"]):focus,
-select:focus {
- border-color: var(--ad-color-accent);
- box-shadow: 0 0 0 2px var(--ad-color-accent-soft);
-}
-
-input:not([type="checkbox"]):not([type="radio"]):disabled,
-select:disabled {
- opacity: 0.5;
- cursor: default;
-}
-
-/* The chevron is the one flagged color exception in this component set:
- CSS cannot point a data-URI background-image at a custom property, so its
- stroke is a literal hex rather than a var(--ad-*) reference. It is picked
- to match --ad-color-text-secondary and commented here so it is not
- mistaken for a stray color. */
-select {
- appearance: none;
- padding-inline-end: var(--ad-space-l);
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235f5d59' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
- background-repeat: no-repeat;
- background-position: right var(--ad-space-xs) center;
-}
-
-input[aria-invalid="true"],
-select[aria-invalid="true"] {
- border-color: var(--ad-color-danger);
- background-color: var(--ad-color-danger-bg);
-}
-
-/* Checkbox / Radio — the real native controls, tinted with accent-color
- instead of a hand-drawn box. This is not just a rename: it deletes the
- custom SVG-checkmark markup entirely and lets the browser draw its own
- (platform-appropriate) check and dot. `role="switch"` is excluded here so
- Switch — a checkbox playing a different role — can style itself below
- without this rule fighting it. A <label> wrapping a checkbox/radio is told
- apart from Field's <label> structurally: it :has() one as a direct child,
- no class required. */
-input[type="checkbox"]:not([role="switch"]),
-input[type="radio"] {
- width: 1.125rem;
- height: 1.125rem;
- margin: 0;
- accent-color: var(--ad-color-accent);
- cursor: pointer;
-}
-input[type="checkbox"]:not([role="switch"]):focus-visible,
-input[type="radio"]:focus-visible {
- outline: 2px solid var(--ad-color-accent);
- outline-offset: 2px;
-}
-
-label:has(> input[type="checkbox"]:not([role="switch"])),
-label:has(> input[type="radio"]) {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 400;
- text-transform: none;
- letter-spacing: normal;
- color: var(--ad-color-text-primary);
-}
-label:has(> input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Switch — for on/off settings only, never a substitute for Checkbox.
- `input[type="checkbox"][role="switch"]` is real ARIA (the correct role for
- a toggle), not an invented hook, but the visual track+thumb needs a second
- element for the thumb's independent position and transition — more than
- `appearance: none` plus pseudo-elements on the input itself can cleanly
- carry — so `.switch` is a deliberate, documented fallback class rather
- than a first choice. */
-.switch {
- display: inline-flex;
- align-items: center;
- gap: var(--ad-space-2xs);
- cursor: pointer;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- color: var(--ad-color-text-primary);
-}
-.switch input[role="switch"] { position: absolute; opacity: 0; width: 2.25rem; height: 1.25rem; margin: 0; }
-
-.switch span {
- position: relative;
- flex: none;
- width: 2.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-border-default);
- transition: background-color var(--ad-dur-base) var(--ad-ease);
-}
-.switch span::after {
- content: "";
- position: absolute;
- inset-block-start: 2px;
- inset-inline-start: 2px;
- width: 1rem;
- height: 1rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-fg);
- box-shadow: var(--ad-shadow-sm);
- transition: translate var(--ad-dur-base) var(--ad-ease);
-}
-.switch input[role="switch"]:checked + span { background: var(--ad-color-accent); }
-.switch input[role="switch"]:checked + span::after { translate: 1rem 0; }
-.switch input[role="switch"]:focus-visible + span { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-.switch:has(input:disabled) { cursor: default; opacity: 0.5; }
-
-/* Rows of fields — used by the settings-form pattern. `<form>`/`<fieldset>`
- are the elements that already mean this, so they are styled bare. A row
- grouping two fields side by side has no element of its own, so it keeps
- one plain class. */
-form {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-s);
- max-width: 28rem;
-}
-.form-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
- gap: var(--ad-space-xs);
-}
-fieldset {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- margin: 0;
- padding: 0;
- border: 0;
-}
-fieldset > legend {
- padding: 0 0 var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- color: var(--ad-color-text-secondary);
-}
-
-/* Badge
- Mono, uppercase, tracked — the catalog-label convention for status and
- meta values (SAVED, OVERDUE, RECOMMENDED). A label, never a button.
-
- A <span> is too generic to style globally — it is used all over running
- prose for unrelated reasons — so Badge gets the one sanctioned class this
- shape needs. Tone is an attribute, not a modifier class. */
-
-.badge {
- --_bg: var(--ad-color-surface-fill);
- --_fg: var(--ad-color-text-secondary);
- --_border: var(--ad-color-border-hairline);
-
- display: inline-flex;
- align-items: center;
- gap: 0.25rem;
- padding: 0.1875rem 0.5rem;
- border: 1px solid var(--_border);
- border-radius: var(--ad-radius-sm);
- background: var(--_bg);
- color: var(--_fg);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- text-transform: uppercase;
- letter-spacing: 0.06em;
- line-height: 1;
- white-space: nowrap;
-}
-
-.badge[data-tone="accent"] { --_bg: var(--ad-color-accent-soft); --_fg: var(--ad-color-accent-ink); --_border: transparent; }
-.badge[data-tone="success"] { --_bg: var(--ad-color-success-bg); --_fg: var(--ad-color-success); --_border: transparent; }
-.badge[data-tone="danger"] { --_bg: var(--ad-color-danger-bg); --_fg: var(--ad-color-danger); --_border: transparent; }
-
-.badge-set {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-2xs);
-}
-
-/* Tag
- A removable mono chip for freeform tags — locations, categories.
- `[data-dashed]` renders an "add tag" affordance instead of a value. Same
- reasoning as Badge: <span> is too generic to select bare, so Tag gets one
- class. The remove control is a real <button>, styled through the
- descendant selector rather than a class of its own. */
-
-.tag {
- display: inline-flex;
- align-items: center;
- gap: 0.375rem;
- padding: 0.25rem 0.625rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-default);
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- line-height: 1;
-}
-
-.tag[data-dashed] {
- background: transparent;
- border-style: dashed;
- color: var(--ad-color-text-tertiary);
- cursor: pointer;
-}
-
-.tag button {
- all: unset;
- cursor: pointer;
- color: var(--ad-color-text-tertiary);
- line-height: 1;
- font-size: 0.75rem;
-}
-.tag button:hover { color: var(--ad-color-text-primary); }
-
-.tag-set {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
-}
-
-/* Card
- Flat surface, hairline border, radius-lg. `[data-elevated]` is opt-in and
- reserved for the one focused/primary card in a view — a dialog, the
- primary capture card — flat is the default everywhere else.
-
- A <div>/<article> is too generic to select bare, so Card keeps one
- sanctioned class. When Card's job is holding a list of rows — the common
- case, entry lists, task lists, settings rows — it is a real <ul class="
- card">, and CardRow is a bare <li> underneath it: no second class needed,
- the row look comes from the `.card > li` descendant selector alone. The
- first row's top border is removed automatically so callers never have to
- override it by hand. */
-
-.card {
- display: flex;
- flex-direction: column;
- margin: 0;
- padding: 0;
- list-style: none;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: none;
- overflow: hidden;
-}
-
-.card[data-elevated] { box-shadow: var(--ad-shadow-float); }
-
-.card > li {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
-}
-.card > li:first-child { border-top: none; }
-
-/* A row whose ENTIRE content is wrapped in a real <button> or <a> — the
- accessible way to make a row clickable — fills the row edge-to-edge and
- picks up a hover fill and pointer cursor. `:only-child` is what tells this
- apart from a row that merely contains a small button among other content
- (a leading checkbox next to a title and a trailing value, say): only a
- button/anchor that IS the row's one and only child means "the whole row
- is the control." */
-.card > li:has(> button:only-child),
-.card > li:has(> a:only-child) {
- padding: 0;
-}
-.card > li > button:only-child,
-.card > li > a:only-child {
- all: unset;
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- width: 100%;
- padding: var(--ad-space-xs) var(--ad-space-s);
- box-sizing: border-box;
- color: inherit;
- font: inherit;
- cursor: pointer;
- transition: background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.card > li > button:only-child:hover,
-.card > li > a:only-child:hover { background: var(--ad-color-surface-fill); }
-
-/* Documentation-only extras: a body/footer pair and a responsive grid, used
- by the prose pages (rationale.md, index.md) to show a Card as a plain
- content tile rather than a data row. Neither is part of Card's props —
- they exist because a content tile's inner layout has no element of its
- own to hang a selector on. */
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-m);
-}
-.card-footer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- margin-top: auto;
- padding: var(--ad-space-xs) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-
-.card[data-link] { transition: border-color var(--ad-dur-fast) var(--ad-ease), box-shadow var(--ad-dur-fast) var(--ad-ease); }
-.card[data-link]:hover { border-color: var(--ad-color-border-default); box-shadow: var(--ad-shadow-sm); }
-.card[data-link]:focus-within { outline: 2px solid var(--ad-color-accent); outline-offset: 2px; }
-
-.card-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
- gap: var(--ad-space-s);
-}
-
-/* Avatar — lives here because it almost never appears outside a card or a
- row (the Loop dashboard's initials chip, Archive's file-type chip). A
- <span> is too generic for a bare selector, so it keeps one class. */
-.avatar {
- --_size: 1.875rem;
-
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--_size);
- height: var(--_size);
- flex: none;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent-soft);
- color: var(--ad-color-accent-ink);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--2);
- font-weight: 600;
- overflow: hidden;
-}
-.avatar[data-square] { border-radius: var(--ad-radius-md); background: var(--ad-color-surface-fill); color: var(--ad-color-text-secondary); border: 1px solid var(--ad-color-border-hairline); }
-.avatar[data-size="sm"] { --_size: 1.5rem; }
-.avatar[data-size="lg"] { --_size: 2.25rem; }
-
-/* Tooltip — a dark mono label on hover, positioned above the child. Pure CSS:
- the trigger and bubble are siblings inside one relatively-positioned span,
- shown on :hover/:focus-within so it works from the keyboard too.
-
- `[role="tooltip"]` is the correct ARIA role for the bubble itself, so it
- doubles as the styling hook — zero classes there. The wrapping span has no
- attribute of its own, but it does not need one: `:has()` picks out "a span
- that contains a [role=tooltip] bubble" precisely, without reaching for a
- class on an otherwise-generic element. */
-span:has(> [role="tooltip"]) {
- position: relative;
- display: inline-flex;
-}
-
-[role="tooltip"] {
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- margin-bottom: 0.375rem;
- padding: 0.25rem 0.5rem;
- border-radius: var(--ad-radius-sm);
- background: var(--ad-color-text-primary);
- color: var(--ad-color-surface-page);
- font-family: var(--ad-font-mono);
- /* 11px is the source's own literal choice — smaller than --ad-step--2, the
- smallest step on the scale, because a tooltip is meant to read as a
- glance-only aside rather than body text. */
- font-size: 11px;
- white-space: nowrap;
- line-height: 1.4;
- z-index: 20;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity var(--ad-dur-fast) var(--ad-ease);
-}
-span:has(> [role="tooltip"]):hover > [role="tooltip"],
-span:has(> [role="tooltip"]):focus-within > [role="tooltip"] {
- opacity: 1;
- visibility: visible;
-}
-
-/* Toast — the real pattern used for delete confirmations: a flat bar with an
- optional destructive action and a dismiss. `[data-fixed]` pins it
- bottom-right for real use; without it the toast stays in document flow for
- documentation. `role="status"` is the correct live-region role for a
- transient status message, so it is both the accessibility hook and the
- style selector — no base class needed. The action and dismiss buttons are
- plain <button>s told apart by `aria-label="Dismiss"`, an attribute they
- need anyway for the icon-only close control. */
-[role="status"] {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- min-width: 20rem;
- padding: var(--ad-space-xs) var(--ad-space-s);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--2);
-}
-[role="status"][data-fixed] {
- position: fixed;
- inset-block-end: var(--ad-space-s);
- inset-inline-end: var(--ad-space-s);
- z-index: 60;
-}
-[role="status"] > span { flex: 1; }
-[role="status"] button {
- all: unset;
- cursor: pointer;
- font-weight: 600;
- color: var(--ad-color-danger);
-}
-[role="status"] button[aria-label="Dismiss"] {
- color: var(--ad-color-text-tertiary);
- font-size: 1rem;
- font-weight: 400;
- line-height: 1;
-}
-[role="status"] button[aria-label="Dismiss"]:hover { color: var(--ad-color-text-primary); }
-
-/* Dialog — the native <dialog> element: a centered modal, flat surface, no
- colored header, hairline dividers between title/body/footer. A <header>
- holds the title and a <footer> holds the actions, matching the elements
- the tag already wants; everything else in between is the body, styled by
- excluding those two rather than by a class of its own.
-
- `.dialog-demo` scopes a static, always-open example to its own preview
- container instead of the viewport, so it can sit safely inside a
- documentation page — this is a doc-only affordance, not part of Dialog's
- contract. It relies on the browser's own dialog centering: the UA
- stylesheet already gives an open <dialog> `position: absolute; inset: 0;
- margin: auto`, which centers it inside the nearest positioned ancestor —
- here, `.dialog-demo` itself. A real `.showModal()` call gets the genuine
- viewport-fixed overlay and `::backdrop` for free; a plain `open` attribute
- (used here so the demo renders without JavaScript) does not paint a
- backdrop at all, since `::backdrop` only exists for a dialog shown
- modally — wire the real open/close state and call `.showModal()` in the
- consuming app. */
-.dialog-demo {
- position: relative;
- min-height: 20rem;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-lg);
-}
-
-dialog {
- width: 26rem;
- max-width: calc(100% - (2 * var(--ad-space-s)));
- height: fit-content;
- padding: 0;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- box-shadow: var(--ad-shadow-float);
- color: var(--ad-color-text-primary);
- overflow: hidden;
-}
-dialog::backdrop {
- background: rgba(20, 18, 14, 0.35);
-}
-dialog > header {
- padding: var(--ad-space-s) var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-sans);
- font-weight: 600;
- font-size: var(--ad-step-0);
- color: var(--ad-color-text-primary);
-}
-dialog > footer {
- display: flex;
- justify-content: flex-end;
- gap: var(--ad-space-2xs);
- padding: var(--ad-space-s) var(--ad-space-m);
- border-top: 1px solid var(--ad-color-border-hairline);
-}
-dialog > *:not(header):not(footer) {
- padding: var(--ad-space-m);
- margin: 0;
- color: var(--ad-color-text-primary);
- font-size: var(--ad-step--1);
-}
-
-/* Tabs
- Follows the real WAI-ARIA tabs pattern: a `[role="tablist"]` of
- `[role="tab"]` buttons controlling `[role="tabpanel"]`s. Those roles are
- required for the pattern to be accessible in the first place, so they
- double as the entire styling contract — no classes at all for the base
- shape. The keyboard wiring lives in assets/js/system.js and is
- variant-agnostic — it only cares about `[data-tabs]` / `[role=tab]`.
-
- Two real variants: `underline` (mono, accent underline — primary section
- nav, the default) and `segmented` (pill track, active segment lifts to the
- surface — filters like All · Overdue · Upcoming, never primary
- navigation), chosen with `data-variant="segmented"` on the tablist since
- neither has a natural attribute of its own. */
-
-/* Every rule below the list container pairs [role="tablist"] with
- [role="tab"] rather than styling [role="tab"] alone — Tab buttons are
- still literal <button> elements, so the compound selector's extra
- specificity is what keeps Button's base styling (button.css) from
- winning the cascade on shared properties like padding and background. */
-
-[role="tablist"] {
- display: flex;
- gap: var(--ad-space-m);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-[role="tablist"] [role="tab"] {
- padding: 0.5rem 0;
- margin-bottom: -1px;
- background: none;
- border: 0;
- border-bottom: 2px solid transparent;
- color: var(--ad-color-text-secondary);
- font-family: var(--ad-font-mono);
- font-size: var(--ad-step--1);
- letter-spacing: 0.02em;
- cursor: pointer;
- transition: color var(--ad-dur-fast) var(--ad-ease), border-color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"] [role="tab"]:hover { color: var(--ad-color-text-primary); }
-[role="tablist"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- border-bottom-color: var(--ad-color-accent);
-}
-
-[role="tablist"][data-variant="segmented"] {
- display: inline-flex;
- gap: 0.125rem;
- padding: 0.1875rem;
- border-bottom: 0;
- background: var(--ad-color-surface-fill);
- border-radius: var(--ad-radius-md);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"] {
- all: unset;
- cursor: pointer;
- padding: 0.375rem 0.875rem;
- border-radius: var(--ad-radius-sm);
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step--1);
- font-weight: 550;
- color: var(--ad-color-text-secondary);
- transition: background-color var(--ad-dur-fast) var(--ad-ease), color var(--ad-dur-fast) var(--ad-ease);
-}
-[role="tablist"][data-variant="segmented"] [role="tab"][aria-selected="true"] {
- color: var(--ad-color-text-primary);
- background: var(--ad-color-surface-card);
- box-shadow: var(--ad-shadow-sm);
-}
-
-[role="tabpanel"] { padding-top: var(--ad-space-s); }
-[role="tabpanel"][hidden] { display: none; }
-[role="tabpanel"]:focus-visible { outline-offset: 4px; }
-
-/* Documentation site chrome. Everything below the `.ad-doc-` prefix belongs
- to this site rather than to the design system it documents — including the
- width/height constants used directly below. The source design system
- defines no container-width tokens at all, so there is nothing under
- `--ad-*` for a doc shell to reach for; the Space foundation page's own
- notes say to omit that group entirely rather than invent one. */
-
-.ad-doc-skip {
- position: absolute;
- inset-inline-start: var(--ad-space-xs);
- inset-block-start: -4rem;
- z-index: 40;
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- box-shadow: var(--ad-shadow-float);
- transition: inset-block-start var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-skip:focus { inset-block-start: var(--ad-space-2xs); }
-
-.ad-doc-header {
- position: sticky;
- inset-block-start: 0;
- z-index: 30;
- height: 3.5rem;
- background: color-mix(in srgb, var(--ad-color-surface-page) 92%, transparent);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-header__inner {
- display: flex;
- align-items: center;
- gap: var(--ad-space-xs);
- height: 100%;
- max-width: 72rem;
- margin-inline: auto;
- padding-inline: var(--ad-space-xs);
-}
-
-.ad-doc-wordmark {
- display: flex;
- align-items: baseline;
- gap: var(--ad-space-2xs);
- color: var(--ad-color-text-primary);
- text-decoration: none;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-0);
- font-weight: 600;
- letter-spacing: -0.01em;
- white-space: nowrap;
-}
-.ad-doc-wordmark:hover { color: var(--ad-color-text-primary); }
-.ad-doc-wordmark__mark {
- width: 1.375rem;
- height: 1.375rem;
- flex: none;
- align-self: center;
- color: var(--ad-color-accent);
-}
-.ad-doc-wordmark__version {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 400;
- color: var(--ad-color-text-tertiary);
-}
-
-.ad-doc-header__actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--ad-space-2xs); }
-
-.ad-doc-layout {
- display: grid;
- grid-template-columns: 16rem minmax(0, 1fr);
- gap: var(--ad-space-l);
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-m) var(--ad-space-xs) var(--ad-space-2xl);
-}
-
-.ad-doc-sidebar {
- position: sticky;
- inset-block-start: calc(3.5rem + var(--ad-space-m));
- align-self: start;
- max-height: calc(100vh - 3.5rem - var(--ad-space-l));
- overflow-y: auto;
- padding-inline-end: var(--ad-space-2xs);
-}
-.ad-doc-nav__group + .ad-doc-nav__group { margin-top: var(--ad-space-s); }
-.ad-doc-nav__heading {
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-.ad-doc-nav__link {
- display: block;
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- margin-inline-start: calc(var(--ad-space-xs) * -1);
- border-inline-start: 2px solid transparent;
- border-radius: 0 var(--ad-radius-sm) var(--ad-radius-sm) 0;
- color: var(--ad-color-text-secondary);
- font-size: var(--ad-step--1);
- text-decoration: none;
- transition: color var(--ad-dur-fast) var(--ad-ease),
- background-color var(--ad-dur-fast) var(--ad-ease);
-}
-.ad-doc-nav__link:hover { color: var(--ad-color-text-primary); background: var(--ad-color-surface-fill); }
-.ad-doc-nav__link[aria-current="page"] {
- color: var(--ad-color-accent-ink);
- border-inline-start-color: var(--ad-color-accent);
- background: var(--ad-color-accent-soft);
- font-weight: 500;
-}
-
-.ad-doc-main {
- min-width: 0;
- /* The design system's own body-text token (--ad-step-0, 18–20px) is right
- for a product screen but too large for long-form documentation prose.
- This site's own copy gets a plain, fixed 16px instead — the token above
- is unchanged, and specimen tables/demos below still show its real
- value. */
- font-size: 1rem;
-}
-.ad-doc-main > * { max-width: 50rem; }
-
-.ad-doc-title { margin-bottom: var(--ad-space-xs); }
-.ad-doc-title__section {
- display: block;
- margin-bottom: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- color: var(--ad-color-accent);
-}
-
-.ad-doc-main h2 {
- margin-block: var(--ad-space-2xl) var(--ad-space-xs);
- padding-bottom: var(--ad-space-2xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-doc-main h3 { margin-block: var(--ad-space-l) var(--ad-space-2xs); }
-.ad-doc-main h4 { margin-block: var(--ad-space-s) var(--ad-space-2xs); }
-.ad-doc-main p,
-.ad-doc-main ul,
-.ad-doc-main ol { max-width: 68ch; }
-.ad-doc-main ul:not([class]),
-.ad-doc-main ol:not([class]) { padding-inline-start: var(--ad-space-s); }
-
-.ad-doc-footer {
- max-width: 72rem;
- margin-inline: auto;
- padding: var(--ad-space-s) var(--ad-space-xs) var(--ad-space-l);
- border-top: 1px solid var(--ad-color-border-hairline);
- color: var(--ad-color-text-tertiary);
- font-size: var(--ad-step--1);
-}
-.ad-doc-footer__inner { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); justify-content: space-between; }
-
-/* `button.ad-doc-nav-toggle` (element + class) rather than a bare class:
- button.css's own base rule is `button:not(.icon-button)`, which is also
- one element + one class in specificity and sets `display: inline-flex` —
- a bare `.ad-doc-nav-toggle { display: none }` loses that fight and the
- toggle stays visible at every width. Matching its specificity here (and
- coming later in the concatenated stylesheet) settles it in source order. */
-button.ad-doc-nav-toggle { display: none; }
-
-@media (max-width: 60rem) {
- .ad-doc-layout { grid-template-columns: minmax(0, 1fr); gap: var(--ad-space-s); }
- .ad-doc-sidebar {
- position: static;
- max-height: none;
- }
- /* The toggle is a normal Button; the panel it opens gets its own card
- treatment. Putting the same card styling on the <aside> wrapper too
- nested a button-shaped box inside an outer box for no reason. */
- .ad-doc-nav {
- margin-top: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- }
- .ad-doc-sidebar[data-collapsed="true"] > .ad-doc-nav { display: none; }
- button.ad-doc-nav-toggle {
- display: flex;
- width: 100%;
- justify-content: space-between;
- }
-}
-
-@media (max-width: 34rem) {
- .ad-doc-wordmark__version { display: none; }
- .ad-doc-layout { padding-inline: var(--ad-space-2xs); }
-}
-
-/* The live-example figure used throughout the docs — see the "How the
- example demos work" section on the Using the CSS page. One class on the
- outer <figure>; everything inside is styled by plain element selectors,
- since figcaption/div/details/summary/pre already say what they are.
- `data-layout` and `data-surface` on the preview <div> distinguish the
- handful of demos that need a non-default arrangement. */
-
-.example {
- margin: var(--ad-space-s) 0 var(--ad-space-l);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
- background: var(--ad-color-surface-card);
- overflow: hidden;
-}
-
-.example figcaption {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-secondary);
-}
-
-.example > div {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: var(--ad-space-xs);
- padding: var(--ad-space-s);
-}
-/* nowrap is load-bearing: a column-direction flex container with wrap enabled
- sizes its single line against the container rather than the content, which
- left every stacked example with a few hundred pixels of dead space. */
-.example > div[data-layout="stack"] { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
-.example > div[data-layout="grid"] {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
- align-items: start;
-}
-.example > div[data-surface="sunken"] { background: var(--ad-color-surface-fill); }
-.example > div > * { min-width: 0; }
-
-.example details {
- border-top: 1px solid var(--ad-color-border-hairline);
- background: var(--ad-color-surface-fill);
-}
-.example summary {
- padding: var(--ad-space-2xs) var(--ad-space-xs);
- font-size: var(--ad-step--2);
- font-weight: 500;
- color: var(--ad-color-text-secondary);
- cursor: pointer;
- list-style: none;
- user-select: none;
- display: flex;
- align-items: center;
- gap: var(--ad-space-2xs);
-}
-.example summary::-webkit-details-marker { display: none; }
-.example summary::before {
- content: "";
- width: 0.5rem;
- height: 0.5rem;
- border-inline-end: 1.5px solid currentColor;
- border-block-end: 1.5px solid currentColor;
- rotate: -45deg;
- transition: rotate var(--ad-dur-fast) var(--ad-ease);
-}
-.example details[open] > summary::before { rotate: 45deg; }
-.example summary:hover { color: var(--ad-color-text-primary); }
-
-.example pre {
- margin: 0;
- padding: var(--ad-space-xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
- tab-size: 2;
-}
-.example pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Standalone fenced code blocks in the prose (unhighlighted — there is no
- syntax highlighter in this build any more, just Kramdown's plain
- <pre><code class="language-*">). */
-.ad-doc-main > pre {
- margin-block: var(--ad-space-xs);
- padding: var(--ad-space-xs);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
- overflow-x: auto;
- font-size: var(--ad-step--2);
- line-height: 1.5;
-}
-.ad-doc-main > pre code { background: none; border: 0; padding: 0; white-space: pre; }
-
-/* Presentation for the token reference tables and swatch grids, plus a
- generic data-table utility. All of this is documentation chrome — the
- design system itself has no Table component (see the note on the removed
- `table`/`progress`/`callout` pages in git history). */
-
-.ad-swatch-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs) var(--ad-space-s);
- padding: 0;
- list-style: none;
-}
-.ad-swatch {
- display: flex;
- flex-direction: column;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
- overflow: hidden;
- background: var(--ad-color-surface-card);
-}
-.ad-swatch__chip {
- display: flex;
- align-items: flex-end;
- justify-content: flex-end;
- height: 4rem;
- padding: var(--ad-space-2xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- font-weight: 600;
-}
-.ad-swatch__meta {
- display: flex;
- flex-direction: column;
- gap: 0.1rem;
- padding: var(--ad-space-2xs);
- border-top: 1px solid var(--ad-color-border-hairline);
- font-family: var(--ad-font-mono);
- font-size: 11px;
-}
-.ad-swatch__hex { color: var(--ad-color-text-primary); text-transform: uppercase; }
-.ad-swatch__ratio { color: var(--ad-color-text-tertiary); }
-
-.ad-alias-row { display: flex; align-items: center; gap: var(--ad-space-2xs); }
-.ad-alias-chip {
- width: 1.5rem;
- height: 1.5rem;
- flex: none;
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-sm);
-}
-.ad-alias-chip--pair { display: flex; }
-.ad-alias-chip--pair > span { flex: 1; }
-
-/* Type specimen rows. */
-.ad-specimen {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: var(--ad-space-3xs);
- padding-block: var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
-}
-.ad-specimen__meta {
- display: flex;
- flex-wrap: wrap;
- gap: var(--ad-space-xs);
- font-family: var(--ad-font-mono);
- font-size: 11px;
- color: var(--ad-color-text-tertiary);
-}
-.ad-specimen__sample {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- color: var(--ad-color-text-primary);
-}
-
-/* Space and radius rulers. */
-.ad-ruler { display: flex; flex-direction: column; gap: var(--ad-space-2xs); }
-.ad-ruler__row { display: grid; grid-template-columns: 6.5rem 4.5rem 1fr; align-items: center; gap: var(--ad-space-xs); font-family: var(--ad-font-mono); font-size: 11px; }
-.ad-ruler__bar { height: 0.75rem; background: var(--ad-color-accent); border-radius: var(--ad-radius-sm); }
-.ad-ruler__num { color: var(--ad-color-text-tertiary); text-align: right; }
-
-.ad-radius-grid, .ad-elevation-grid, .ad-motion-grid, .ad-accent-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-xs);
- padding: 0;
- list-style: none;
-}
-.ad-radius-demo {
- height: 4.5rem;
- background: var(--ad-color-accent-soft);
- border: 1px solid var(--ad-color-accent);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-elevation-demo {
- height: 4.5rem;
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-lg);
- margin-bottom: var(--ad-space-2xs);
-}
-.ad-motion-demo {
- height: 4.5rem;
- display: grid;
- place-items: center;
- background: var(--ad-color-surface-fill);
- border: 1px solid var(--ad-color-border-hairline);
- border-radius: var(--ad-radius-md);
- margin-bottom: var(--ad-space-2xs);
- cursor: pointer;
- overflow: hidden;
-}
-.ad-motion-demo__dot {
- width: 1.25rem;
- height: 1.25rem;
- border-radius: var(--ad-radius-full);
- background: var(--ad-color-accent);
- translate: -3rem 0;
- transition-property: translate;
- transition-duration: var(--ad-dur-base);
- transition-timing-function: var(--ad-ease);
-}
-.ad-motion-demo:hover .ad-motion-demo__dot,
-.ad-motion-demo:focus-visible .ad-motion-demo__dot { translate: 3rem 0; }
-
-.ad-accent-demo {
- height: 4.5rem;
- display: flex;
- align-items: flex-end;
- padding: var(--ad-space-2xs);
- border-radius: var(--ad-radius-md);
- color: #fff;
- font-family: var(--ad-font-mono);
- font-size: 11px;
- margin-bottom: var(--ad-space-2xs);
-}
-
-/* Token names read `<code>` sitewide, which already carries a mono chip
- look for running prose (see :not(pre) > code in base/typography.css).
- Inside these specimen/swatch/ruler rows the old `.ad-token-name` class was
- plain mono text with no chip, so `<code>` is flattened back to that look
- here the same way table cells are. */
-.ad-swatch code, .ad-specimen code, .ad-ruler code, .ad-alias-row code {
- background: none;
- border: 0;
- padding: 0;
- font-size: var(--ad-step--2);
- color: var(--ad-color-text-primary);
- white-space: nowrap;
-}
-
-/* A documentation aside. Like `<table>`, this is site chrome for the prose
- itself, not a system component — the real system has no Callout. */
-.ad-callout {
- margin-block: var(--ad-space-s);
- padding: var(--ad-space-xs) var(--ad-space-s);
- border: 1px solid var(--ad-color-border-hairline);
- border-left: 3px solid var(--ad-color-accent);
- border-radius: var(--ad-radius-md);
- background: var(--ad-color-surface-fill);
-}
-/* Generic reference tables (component APIs, alias tables, the contrast
- contract). `<table>` IS a table — no class needed to say so. Every table
- on this site uses the one compact density, so there is no separate
- modifier for it. `display: block` plus `overflow-x: auto` gives the table
- its own horizontal scrollbar on narrow viewports without a wrapper div;
- the anonymous table box the browser generates around `<thead>`/`<tbody>`
- still does the row/column layout. `<code>` replaces the old
- `.ad-token-name` / `.ad-table__code` cells — it is already styled
- sitewide, just re-flattened here to a plain mono run instead of the
- chip-with-border look prose code gets, to match this table's original
- look. `.num` is the one sanctioned class left, for right-aligned numeric
- columns — there is no attribute that means "this column is a number". */
-table { width: 100%; border-collapse: collapse; font-size: var(--ad-step--1); display: block; overflow-x: auto; }
-table th, table td {
- padding: var(--ad-space-3xs) var(--ad-space-xs);
- border-bottom: 1px solid var(--ad-color-border-hairline);
- text-align: left;
- vertical-align: top;
-}
-table th { font-family: var(--ad-font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ad-color-text-secondary); font-weight: 500; }
-table code { background: none; border: 0; padding: 0; font-size: var(--ad-step--2); white-space: nowrap; }
-.num { text-align: right; font-variant-numeric: tabular-nums; }
-
-/* Home page. */
-.ad-hero { padding-block: var(--ad-space-m) var(--ad-space-l); }
-.ad-hero__title {
- font-size: var(--ad-step-4);
- margin-bottom: var(--ad-space-xs);
-}
-.ad-hero__actions { display: flex; flex-wrap: wrap; gap: var(--ad-space-xs); margin-top: var(--ad-space-s); }
-.ad-stat-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
- gap: var(--ad-space-xs);
- margin-block: var(--ad-space-l);
- padding: var(--ad-space-xs);
- background: var(--ad-color-surface-card);
- border: 1px solid var(--ad-color-border-default);
- border-radius: var(--ad-radius-lg);
-}
-.ad-stat__value {
- display: block;
- font-family: var(--ad-font-sans);
- font-size: var(--ad-step-2);
- font-weight: 600;
- line-height: 1.16;
- font-variant-numeric: tabular-nums;
-}
-.ad-stat__label {
- font-family: var(--ad-font-mono);
- font-size: 11px;
- letter-spacing: 0.06em;
- text-transform: uppercase;
- color: var(--ad-color-text-tertiary);
-}
-
-/* Card chrome. The pane supplies the frame; this just insets the page. */
-body { padding: var(--ad-space-l) var(--ad-space-m); }
-.ad-doc-main { max-width: 50rem; margin-inline: auto; }
-.ad-doc-main > * { max-width: none; }
-</style>
-</head>
-<body>
-<main class="ad-doc-main">
-<header class="ad-doc-title"><span class="ad-doc-title__section">Patterns</span>
- <h1>Loop — task dashboard</h1>
-</header>
-<p class="ad-lead">A recurring-task web dashboard. Dense rows, mono meta columns, overdue in danger red, one primary action. A generic demonstration of the system, not a recreation of any one source project's actual screens.</p>
-<p>Loop is not a real product — it is the system’s own reference layout for a
-dense, table-ish list screen: the shape <code>kejadlen/ketchup</code> (a recurring-task
-tracker) would take if it were rebuilt on this token set. Every visible value
-below is a component from this system; nothing here is page-specific CSS
-beyond a couple of inline widths.</p>
-
-<figure class="example">
-<figcaption>Loop</figcaption>
-<div data-layout="stack">
-<div style="border: 1px solid var(--ad-color-border-hairline); border-radius: var(--ad-radius-lg); overflow: hidden; background: var(--ad-color-surface-page);">
- <header style="display:flex; align-items:center; gap: var(--ad-space-s); padding: var(--ad-space-s) var(--ad-space-l); border-bottom: 1px solid var(--ad-color-border-hairline);">
- <span style="font-family: var(--ad-font-mono); font-weight:600; letter-spacing:0.02em; font-size: var(--ad-step-0);">Loop</span>
- <div style="flex:1;"></div>
- <button data-variant="primary" data-size="sm">
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
- New
- </button>
- <span class="avatar">km</span>
- </header>
- <div style="display:flex;">
- <div style="flex:1; min-width:0; max-width: 34rem; padding: var(--ad-space-l);">
- <section style="margin-bottom: var(--ad-space-l);">
- <div style="display:flex; align-items:baseline; gap: var(--ad-space-2xs); margin-bottom: var(--ad-space-s);">
- <span class="type-label" style="color: var(--ad-color-danger);">Overdue</span>
- <span class="badge" data-tone="danger">2</span>
- </div>
- <ul class="card" style="border:none; border-radius:0; background:none;">
- <li style="border-top: 1px solid var(--ad-color-border-hairline);">
- <button aria-label="Complete" style="all:unset; width:18px; height:18px; border-radius:4px; flex-shrink:0; cursor:pointer; border: 1.5px solid var(--ad-color-danger);"></button>
- <div style="flex:1; min-width:0;">
- <div style="font-weight:500; color: var(--ad-color-danger);">Call Mom</div>
- <div class="type-mono" style="color: var(--ad-color-text-tertiary); font-size: var(--ad-step--2);">every 2 weeks</div>
- </div>
- <span class="type-mono" style="color: var(--ad-color-danger); font-size: var(--ad-step--2); white-space:nowrap;">3d overdue</span>
- </li>
- <li>
- <button aria-label="Complete" style="all:unset; width:18px; height:18px; border-radius:4px; flex-shrink:0; cursor:pointer; border: 1.5px solid var(--ad-color-danger);"></button>
- <div style="flex:1; min-width:0;">
- <div style="font-weight:500; color: var(--ad-color-danger);">Water the ferns</div>
- <div class="type-mono" style="color: var(--ad-color-text-tertiary); font-size: var(--ad-step--2);">every 5 days</div>
- </div>
- <span class="type-mono" style="color: var(--ad-color-danger); font-size: var(--ad-step--2); white-space:nowrap;">1d overdue</span>
- </li>
- </ul>
- </section>
- <section>
- <div class="type-label" style="margin-bottom: var(--ad-space-s);">Upcoming</div>
- <ul class="card" style="border:none; border-radius:0; background:none;">
- <li style="border-top: 1px solid var(--ad-color-border-hairline);">
- <button aria-label="Complete" style="all:unset; width:18px; height:18px; border-radius:4px; flex-shrink:0; cursor:pointer; border: 1.5px solid var(--ad-color-text-secondary);"></button>
- <div style="flex:1; min-width:0;">
- <div style="font-weight:500;">Renew passport</div>
- <div class="type-mono" style="color: var(--ad-color-text-tertiary); font-size: var(--ad-step--2);">every 10 years</div>
- </div>
- <span class="type-mono" style="color: var(--ad-color-text-secondary); font-size: var(--ad-step--2); white-space:nowrap;">in 3 months</span>
- </li>
- <li>
- <button aria-label="Complete" style="all:unset; width:18px; height:18px; border-radius:4px; flex-shrink:0; cursor:pointer; border: 1.5px solid var(--ad-color-text-secondary);"></button>
- <div style="flex:1; min-width:0;">
- <div style="font-weight:500;">Dentist checkup</div>
- <div class="type-mono" style="color: var(--ad-color-text-tertiary); font-size: var(--ad-step--2);">every 6 months</div>
- </div>
- <span class="type-mono" style="color: var(--ad-color-text-secondary); font-size: var(--ad-step--2); white-space:nowrap;">in 2 weeks</span>
- </li>
- <li>
- <button aria-label="Complete" style="all:unset; width:18px; height:18px; border-radius:4px; flex-shrink:0; cursor:pointer; border: 1.5px solid var(--ad-color-text-secondary);"></button>
- <div style="flex:1; min-width:0;">
- <div style="font-weight:500;">Rotate mattress</div>
- <div class="type-mono" style="color: var(--ad-color-text-tertiary); font-size: var(--ad-step--2);">every 6 months</div>
- </div>
- <span class="type-mono" style="color: var(--ad-color-text-secondary); font-size: var(--ad-step--2); white-space:nowrap;">in 5 weeks</span>
- </li>
- </ul>
- </section>
- </div>
- <aside style="width: 15rem; flex-shrink:0; background: var(--ad-color-surface-fill); border-left: 1px solid var(--ad-color-border-hairline); padding: var(--ad-space-l);">
- <div class="type-label" style="margin-bottom: var(--ad-space-s);">This week</div>
- <div style="display:flex; background: var(--ad-color-surface-card); border: 1px solid var(--ad-color-border-hairline); border-radius: var(--ad-radius-md); overflow:hidden; margin-bottom: var(--ad-space-l);">
- <div style="flex:1; display:flex; flex-direction:column; align-items:center; gap:4px; padding: 8px 0; border-right: 1px solid var(--ad-color-border-hairline);">
- <span class="type-mono" style="font-size:9px; color: var(--ad-color-text-tertiary); text-transform:uppercase;">S</span>
- <span style="font-size:13px; font-weight:600; color: var(--ad-color-text-primary);">0</span>
- </div>
- <div style="flex:1; display:flex; flex-direction:column; align-items:center; gap:4px; padding: 8px 0; border-right: 1px solid var(--ad-color-border-hairline);">
- <span class="type-mono" style="font-size:9px; color: var(--ad-color-text-tertiary); text-transform:uppercase;">M</span>
- <span style="font-size:13px; font-weight:600; color: var(--ad-color-text-primary);">1</span>
- </div>
- <div style="flex:1; display:flex; flex-direction:column; align-items:center; gap:4px; padding: 8px 0; border-right: 1px solid var(--ad-color-border-hairline);">
- <span class="type-mono" style="font-size:9px; color: var(--ad-color-text-tertiary); text-transform:uppercase;">T</span>
- <span style="font-size:13px; font-weight:600; color: var(--ad-color-text-primary);">0</span>
- </div>
- <div style="flex:1; display:flex; flex-direction:column; align-items:center; gap:4px; padding: 8px 0; background: var(--ad-color-accent-soft); border-right: 1px solid var(--ad-color-border-hairline);">
- <span class="type-mono" style="font-size:9px; color: var(--ad-color-text-tertiary); text-transform:uppercase;">W</span>
- <span style="font-size:13px; font-weight:600; color: var(--ad-color-accent-ink);">2</span>
- </div>
- <div style="flex:1; display:flex; flex-direction:column; align-items:center; gap:4px; padding: 8px 0; border-right: 1px solid var(--ad-color-border-hairline);">
- <span class="type-mono" style="font-size:9px; color: var(--ad-color-text-tertiary); text-transform:uppercase;">T</span>
- <span style="font-size:13px; font-weight:600; color: var(--ad-color-text-primary);">0</span>
- </div>
- <div style="flex:1; display:flex; flex-direction:column; align-items:center; gap:4px; padding: 8px 0; border-right: 1px solid var(--ad-color-border-hairline);">
- <span class="type-mono" style="font-size:9px; color: var(--ad-color-text-tertiary); text-transform:uppercase;">F</span>
- <span style="font-size:13px; font-weight:600; color: var(--ad-color-text-primary);">1</span>
- </div>
- <div style="flex:1; display:flex; flex-direction:column; align-items:center; gap:4px; padding: 8px 0; ">
- <span class="type-mono" style="font-size:9px; color: var(--ad-color-text-tertiary); text-transform:uppercase;">S</span>
- <span style="font-size:13px; font-weight:600; color: var(--ad-color-text-primary);">0</span>
- </div>
- </div>
- <div class="type-label" style="margin-bottom: var(--ad-space-2xs);">Series</div>
- <div>
- <div style="padding: var(--ad-space-2xs) 0; font-size: var(--ad-step--1); color: var(--ad-color-text-secondary);">Call Mom</div>
- <div style="padding: var(--ad-space-2xs) 0; border-top: 1px solid var(--ad-color-border-hairline); font-size: var(--ad-step--1); color: var(--ad-color-text-secondary);">Water the ferns</div>
- <div style="padding: var(--ad-space-2xs) 0; border-top: 1px solid var(--ad-color-border-hairline); font-size: var(--ad-step--1); color: var(--ad-color-text-secondary);">Renew passport</div>
- </div>
- </aside>
- </div>
-</div>
-</div>
-</figure>
-
-<h2 id="the-new-series-dialog">The New series dialog</h2>
-
-<figure class="example">
-<figcaption>New series</figcaption>
-<div data-layout="stack">
-<div class="dialog-demo" style="min-height: 36rem;">
- <dialog open="" style="width: 22rem;">
- <header>New series</header>
- <div>
- <div style="display:flex; flex-direction:column; gap: var(--ad-space-s);">
- <label class="field">
- Note
- <input placeholder="Call Mom" />
- <small>First line becomes the display name.</small>
- </label>
- <div class="form-row">
- <label class="field">
- Every
- <input type="number" placeholder="2" />
- </label>
- <label class="field">
- Unit
- <select><option>Day</option><option selected="">Week</option><option>Month</option><option>Year</option></select>
- </label>
- </div>
- </div>
- </div>
- <footer>
- <button>Cancel</button>
- <button data-variant="primary">Create</button>
- </footer>
- </dialog>
-</div>
-</div>
-</figure>
-
-<h2 id="after-completing-a-task">After completing a task</h2>
-
-<figure class="example">
-<figcaption>Toast</figcaption>
-<div>
-<div role="status">
- <span>Completed "Call Mom"</span>
- <button aria-label="Dismiss">×</button>
-</div>
-</div>
-</figure>
-
-<h2 id="what-this-screen-is-testing">What this screen is testing</h2>
-
-<ul>
- <li><strong>Dense rows next to a mono meta column.</strong> A recurring-task list is
-fundamentally tabular even though it never touches an actual <code><table></code>.</li>
- <li><strong>Overdue in <code>--ad-color-danger</code>, everywhere at once.</strong> Row text, the
-complete-button border, and the trailing meta all pick it up from the same
-<code>overdue</code> state — color never drifts row to row.</li>
- <li><strong>One primary action.</strong> <code>New</code> is the only accent-filled control on screen;
-everything else is neutral or bordered.</li>
- <li><strong>Accent used exactly once, decoratively.</strong> The “km” avatar and the
-highlighted day both use <code>--ad-color-accent-soft</code> / <code>-ink</code> — never the raw
-accent fill outside of <code>New</code>.</li>
-</ul>
-</main>
-<script>
-// Behavior for the pieces of the system that need it. Everything else is
-// CSS and semantic HTML on purpose — a design system that only works with
-// JavaScript running is a component library with extra steps.
-(function () {
- "use strict";
-
- var STORAGE_KEY = "ad-theme";
-
- function readStored() {
- try {
- return localStorage.getItem(STORAGE_KEY);
- } catch (error) {
- return null;
- }
- }
-
- function writeStored(value) {
- try {
- localStorage.setItem(STORAGE_KEY, value);
- } catch (error) {
- /* Nothing to do — the media query still gives a sensible default. */
- }
- }
-
- function systemPrefersDark() {
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
- }
-
- function currentTheme() {
- var explicit = document.documentElement.getAttribute("data-theme");
- if (explicit) return explicit;
- return systemPrefersDark() ? "dark" : "light";
- }
-
- function paintToggle(theme) {
- document.querySelectorAll("[data-theme-toggle]").forEach(function (toggle) {
- var next = theme === "dark" ? "light" : "dark";
- toggle.querySelectorAll("[data-theme-icon]").forEach(function (icon) {
- icon.hidden = icon.dataset.themeIcon !== theme;
- });
- toggle.setAttribute("aria-label", "Switch to the " + next + " theme");
- toggle.setAttribute("title", "Switch to the " + next + " theme");
- var label = toggle.querySelector("[data-theme-label]");
- if (label) label.textContent = "Switch to the " + next + " theme";
- });
- }
-
- function setUpTheme() {
- paintToggle(currentTheme());
-
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-theme-toggle]");
- if (!toggle) return;
-
- var next = currentTheme() === "dark" ? "light" : "dark";
- document.documentElement.setAttribute("data-theme", next);
- writeStored(next);
- paintToggle(next);
- });
-
- // Follow the OS while the reader has not made an explicit choice.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", function () {
- if (!readStored()) paintToggle(currentTheme());
- });
- }
-
- // Tabs, wired to the WAI-ARIA authoring practices: arrows move, Home/End
- // jump, and only the selected tab stays in the tab order.
- function setUpTabs() {
- document.querySelectorAll("[data-tabs]").forEach(function (root) {
- var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
- if (!tabs.length) return;
-
- function select(tab, focus) {
- tabs.forEach(function (candidate) {
- var selected = candidate === tab;
- candidate.setAttribute("aria-selected", String(selected));
- candidate.tabIndex = selected ? 0 : -1;
- var panel = document.getElementById(candidate.getAttribute("aria-controls"));
- if (panel) panel.hidden = !selected;
- });
- if (focus) tab.focus();
- }
-
- root.addEventListener("click", function (event) {
- var tab = event.target.closest('[role="tab"]');
- if (tab) select(tab, false);
- });
-
- root.addEventListener("keydown", function (event) {
- var index = tabs.indexOf(document.activeElement);
- if (index === -1) return;
-
- var next = null;
- if (event.key === "ArrowRight") next = tabs[(index + 1) % tabs.length];
- else if (event.key === "ArrowLeft") next = tabs[(index - 1 + tabs.length) % tabs.length];
- else if (event.key === "Home") next = tabs[0];
- else if (event.key === "End") next = tabs[tabs.length - 1];
-
- if (next) {
- event.preventDefault();
- select(next, true);
- }
- });
-
- select(tabs.filter(function (tab) {
- return tab.getAttribute("aria-selected") === "true";
- })[0] || tabs[0], false);
- });
- }
-
- function setUpNavToggle() {
- document.addEventListener("click", function (event) {
- var toggle = event.target.closest("[data-nav-toggle]");
- if (!toggle) return;
-
- var sidebar = toggle.closest("[data-sidebar]");
- var collapsed = sidebar.dataset.collapsed !== "false";
- sidebar.dataset.collapsed = String(!collapsed);
- toggle.setAttribute("aria-expanded", String(collapsed));
- });
- }
-
- setUpTheme();
- setUpTabs();
- setUpNavToggle();
-})();
-
-</script>
-</body>
-</html>