@hanzo/design 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,18 +3,24 @@ import React from 'react'
3
3
  /** Native-select build of the @hanzo/ui Select — same chrome, no portal. */
4
4
  export function Select({ options = [], value, onChange, placeholder, style, children, ...rest }) {
5
5
  const [focus, setFocus] = React.useState(false)
6
+ const [hover, setHover] = React.useState(false)
6
7
  return (
7
8
  <span style={{position:'relative',display:'inline-flex',alignItems:'center',width:'100%'}}>
9
+ {/* Same chrome as Input and Textarea — radius, hover lift, focus halo. */}
8
10
  <select
9
11
  value={value}
10
12
  onChange={(e)=>onChange && onChange(e.target.value)}
11
13
  onFocus={()=>setFocus(true)} onBlur={()=>setFocus(false)}
14
+ onMouseEnter={()=>setHover(true)} onMouseLeave={()=>setHover(false)}
12
15
  style={{
13
16
  appearance:'none',width:'100%',height:36,padding:'0 32px 0 12px',
14
17
  fontFamily:'var(--font-sans)',fontSize:'var(--text-control)',color:'var(--foreground)',
15
- background:'var(--surface-2)',border:'1px solid ' + (focus ? 'var(--border-focus)' : 'var(--border-control)'),
16
- borderRadius:'var(--radius-sm)',cursor:'pointer',
17
- transition:'border-color var(--duration-fast) var(--ease-out)',
18
+ background: hover && !focus ? 'var(--surface-3)' : 'var(--surface-2)',
19
+ border:'1px solid ' + (focus ? 'var(--border-focus)' : 'var(--border-control)'),
20
+ borderRadius:'var(--radius-md)',cursor:'pointer',
21
+ outline:'none',
22
+ boxShadow: focus ? 'var(--ring-focus)' : 'none',
23
+ transition:'border-color var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out)',
18
24
  ...style,
19
25
  }}
20
26
  {...rest}
@@ -1,18 +1,27 @@
1
1
  import React from 'react'
2
2
 
3
+ // Same chrome as Input, to the pixel — radius, hover lift, focus halo. A
4
+ // textarea that rounds one step tighter than the field above it and lights up
5
+ // differently on focus is the kind of drift nobody reports and everybody feels.
3
6
  export function Textarea({ rows = 4, style, ...rest }) {
4
7
  const [focus, setFocus] = React.useState(false)
8
+ const [hover, setHover] = React.useState(false)
5
9
  return (
6
10
  <textarea
7
11
  rows={rows}
8
12
  onFocus={(e)=>{setFocus(true);rest.onFocus&&rest.onFocus(e)}}
9
13
  onBlur={(e)=>{setFocus(false);rest.onBlur&&rest.onBlur(e)}}
14
+ onMouseEnter={()=>setHover(true)}
15
+ onMouseLeave={()=>setHover(false)}
10
16
  style={{
11
17
  width:'100%',padding:'8px 12px',resize:'vertical',
12
18
  fontFamily:'var(--font-sans)',fontSize:'var(--text-control)',lineHeight:'var(--leading-relaxed)',color:'var(--foreground)',
13
- background:'var(--surface-2)',border:'1px solid ' + (focus ? 'var(--border-focus)' : 'var(--border-control)'),
14
- borderRadius:'var(--radius-sm)',
15
- transition:'border-color var(--duration-fast) var(--ease-out)',
19
+ background: hover && !focus ? 'var(--surface-3)' : 'var(--surface-2)',
20
+ border:'1px solid ' + (focus ? 'var(--border-focus)' : 'var(--border-control)'),
21
+ borderRadius:'var(--radius-md)',
22
+ outline:'none',
23
+ boxShadow: focus ? 'var(--ring-focus)' : 'none',
24
+ transition:'border-color var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out)',
16
25
  ...style,
17
26
  }}
18
27
  {...rest}
@@ -8,7 +8,7 @@
8
8
  .meta{font-size:10px;color:var(--neutral-600);font-family:var(--font-mono);white-space:nowrap}
9
9
  </style></head><body>
10
10
  <div style="display:flex;gap:16px;align-items:stretch">
11
- <div style="flex:1;padding:14px;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:var(--radius-lg);font-size:12px;color:var(--neutral-400)">flat — hairline only<div class="n" style="margin-top:8px">--shadow-none</div></div>
12
- <div style="flex:1;padding:14px;background:var(--surface-overlay);border:1px solid var(--border-hairline);border-radius:var(--radius-xl);box-shadow:var(--shadow-floating);font-size:12px;color:var(--neutral-400)">floating — menu, dialog, composer<div class="n" style="margin-top:8px">--shadow-floating</div></div>
13
- <div style="flex:1;position:relative;overflow:hidden;background:#000;border:1px solid var(--border-hairline);border-radius:var(--radius-lg)"><div style="position:absolute;left:50%;top:50%;width:220px;height:220px;transform:translate(-50%,-50%);background:var(--glow-hero);filter:blur(60px)"></div><div style="position:relative;padding:14px;font-size:12px;color:var(--neutral-300)">ambient glow<div class="n" style="margin-top:8px">--glow-hero</div></div></div>
11
+ <div style="flex:1;padding:14px;background:var(--surface-card);border:1px solid var(--border);border-radius:var(--radius-lg);font-size:12px;color:var(--neutral-400)">flat — hairline only<div class="n" style="margin-top:8px">--shadow-none</div></div>
12
+ <div style="flex:1;padding:14px;background:var(--surface-overlay);border:1px solid var(--border);border-radius:var(--radius-xl);box-shadow:var(--shadow-floating);font-size:12px;color:var(--neutral-400)">floating — menu, dialog, composer<div class="n" style="margin-top:8px">--shadow-floating</div></div>
13
+ <div style="flex:1;position:relative;overflow:hidden;background:#000;border:1px solid var(--border);border-radius:var(--radius-lg)"><div style="position:absolute;left:50%;top:50%;width:220px;height:220px;transform:translate(-50%,-50%);background:var(--glow-hero);filter:blur(60px)"></div><div style="position:relative;padding:14px;font-size:12px;color:var(--neutral-300)">ambient glow<div class="n" style="margin-top:8px">--glow-hero</div></div></div>
14
14
  </div></body></html>
@@ -8,9 +8,9 @@
8
8
  .meta{font-size:10px;color:var(--neutral-600);font-family:var(--font-mono);white-space:nowrap}
9
9
  </style></head><body>
10
10
  <div style="display:flex;gap:10px">
11
- <img src="../assets/brand/hero-visualization.png" alt="" style="width:33%;height:150px;object-fit:cover;border-radius:var(--radius-lg);border:1px solid var(--border-hairline)">
12
- <img src="../assets/brand/industry-cloud.png" alt="" style="width:33%;height:150px;object-fit:cover;border-radius:var(--radius-lg);border:1px solid var(--border-hairline)">
13
- <img src="../assets/brand/industry-infrastructure.png" alt="" style="width:33%;height:150px;object-fit:cover;border-radius:var(--radius-lg);border:1px solid var(--border-hairline)">
11
+ <img src="../assets/brand/hero-visualization.png" alt="" style="width:33%;height:150px;object-fit:cover;border-radius:var(--radius-lg);border:1px solid var(--border)">
12
+ <img src="../assets/brand/industry-cloud.png" alt="" style="width:33%;height:150px;object-fit:cover;border-radius:var(--radius-lg);border:1px solid var(--border)">
13
+ <img src="../assets/brand/industry-infrastructure.png" alt="" style="width:33%;height:150px;object-fit:cover;border-radius:var(--radius-lg);border:1px solid var(--border)">
14
14
  </div>
15
15
  <div class="meta" style="margin-top:10px">assets/brand/* · cool-toned, low-key, no warm gradients, no illustration style</div>
16
16
  </body></html>
@@ -8,7 +8,7 @@
8
8
  .meta{font-size:10px;color:var(--neutral-600);font-family:var(--font-mono);white-space:nowrap}
9
9
  .dm{animation:hanzo-slide-up-fade 1.6s var(--ease-out) infinite}.dg{animation:hanzo-glow 9s var(--ease-in-out) infinite}</style></head><body>
10
10
  <div style="display:flex;gap:16px;align-items:stretch">
11
- <div style="flex:1;padding:14px;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:var(--radius-lg);overflow:hidden"><div class="dm" style="font-size:12px;color:var(--neutral-200)">entry: opacity 0→1, y 20→0</div><div class="n" style="margin-top:10px">500ms · ease-out · 60ms stagger</div></div>
12
- <div style="flex:1;padding:14px;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:var(--radius-lg);position:relative;overflow:hidden"><div class="dg" style="position:absolute;inset:-40px;background:var(--glow-hero);filter:blur(50px)"></div><div style="position:relative;font-size:12px;color:var(--neutral-200)">ambient glow breathe</div><div class="n" style="position:relative;margin-top:10px">9s · scale 1→1.08</div></div>
13
- <div style="flex:1;padding:14px;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:var(--radius-lg)"><div style="font-size:12px;color:var(--neutral-200)">hover: colour only</div><div class="n" style="margin-top:10px">150ms · transition-colors</div></div>
11
+ <div style="flex:1;padding:14px;background:var(--surface-card);border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden"><div class="dm" style="font-size:12px;color:var(--neutral-200)">entry: opacity 0→1, y 20→0</div><div class="n" style="margin-top:10px">500ms · ease-out · 60ms stagger</div></div>
12
+ <div style="flex:1;padding:14px;background:var(--surface-card);border:1px solid var(--border);border-radius:var(--radius-lg);position:relative;overflow:hidden"><div class="dg" style="position:absolute;inset:-40px;background:var(--glow-hero);filter:blur(50px)"></div><div style="position:relative;font-size:12px;color:var(--neutral-200)">ambient glow breathe</div><div class="n" style="position:relative;margin-top:10px">9s · scale 1→1.08</div></div>
13
+ <div style="flex:1;padding:14px;background:var(--surface-card);border:1px solid var(--border);border-radius:var(--radius-lg)"><div style="font-size:12px;color:var(--neutral-200)">hover: colour only</div><div class="n" style="margin-top:10px">150ms · transition-colors</div></div>
14
14
  </div></body></html>
@@ -8,10 +8,10 @@
8
8
  .meta{font-size:10px;color:var(--neutral-600);font-family:var(--font-mono);white-space:nowrap}
9
9
  </style></head><body>
10
10
  <div class="g">
11
- <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:6px"></div><div class="n">6px</div><div class="v">button · input</div></div>
12
- <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:12px"></div><div class="n">12px</div><div class="v">card</div></div>
13
- <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:16px"></div><div class="n">16px</div><div class="v">panel</div></div>
14
- <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:24px"></div><div class="n">24px</div><div class="v">story card</div></div>
15
- <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:28px"></div><div class="n">28px</div><div class="v">composer</div></div>
16
- <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border-hairline);border-radius:999px"></div><div class="n">999px</div><div class="v">pill · avatar</div></div>
11
+ <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border);border-radius:6px"></div><div class="n">6px</div><div class="v">button · input</div></div>
12
+ <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border);border-radius:12px"></div><div class="n">12px</div><div class="v">card</div></div>
13
+ <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border);border-radius:16px"></div><div class="n">16px</div><div class="v">panel</div></div>
14
+ <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border);border-radius:24px"></div><div class="n">24px</div><div class="v">story card</div></div>
15
+ <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border);border-radius:28px"></div><div class="n">28px</div><div class="v">composer</div></div>
16
+ <div class="sw"><div style="height:48px;background:var(--surface-card);border:1px solid var(--border);border-radius:999px"></div><div class="n">999px</div><div class="v">pill · avatar</div></div>
17
17
  </div></body></html>
@@ -1,16 +1,17 @@
1
- <!-- @dsCard group="Colors" viewport="700x150" name="Borders" subtitle="Three hairline weights carry all the structure" -->
1
+ <!-- @dsCard group="Colors" viewport="820x160" name="Borders" subtitle="One alpha ladder, graded by duty — only the focus ring owes a ratio" -->
2
2
  <!doctype html><html class="dark"><head><meta charset="utf-8"><title>Borders</title><link rel="stylesheet" href="../styles.css">
3
3
  <style>body{margin:0;padding:16px 20px;background:#000;font-family:var(--font-sans);color:var(--foreground)}
4
- .g{display:flex;gap:10px;flex-wrap:wrap}.sw{flex:1;min-width:64px}.chip{height:56px;border-radius:8px;border:1px solid var(--white-10)}
4
+ .g{display:flex;gap:10px;flex-wrap:wrap}.sw{flex:1;min-width:110px}.chip{height:56px;border-radius:8px;border:1px solid var(--white-10)}
5
5
  .n{margin-top:6px;font-size:10px;font-weight:600;letter-spacing:.06em;color:var(--neutral-300);font-family:var(--font-mono)}
6
6
  .v{font-size:9px;color:var(--neutral-600);font-family:var(--font-mono)}
7
7
  .row{display:flex;align-items:baseline;gap:14px}.mono{font-family:var(--font-mono)}
8
8
  .meta{font-size:10px;color:var(--neutral-600);font-family:var(--font-mono);white-space:nowrap}
9
9
  </style></head><body>
10
10
  <div class="g">
11
- <div class="sw"><div class="chip" style="background:var(--card);border:1px solid var(--border)"></div><div class="n">--border</div><div class="v">#1f1f1f</div></div>
12
- <div class="sw"><div class="chip" style="background:var(--card);border:1px solid var(--border-hairline)"></div><div class="n">--border-hairline</div><div class="v">neutral-800</div></div>
13
- <div class="sw"><div class="chip" style="background:var(--card);border:1px solid var(--border-card)"></div><div class="n">--border-card</div><div class="v">white/10</div></div>
14
- <div class="sw"><div class="chip" style="background:var(--card);border:1px solid var(--border-strong)"></div><div class="n">--border-strong</div><div class="v">neutral-700 · hover</div></div>
15
- <div class="sw"><div class="chip" style="background:var(--card);border:1px solid var(--ring)"></div><div class="n">--ring</div><div class="v">#333 · focus</div></div>
16
- </div></body></html>
11
+ <div class="sw"><div class="chip" style="background:var(--card);border:1px solid var(--border)"></div><div class="n">--border</div><div class="v">white/10 · hairline</div></div>
12
+ <div class="sw"><div class="chip" style="background:var(--card);border:1px solid var(--border-strong)"></div><div class="n">--border-strong</div><div class="v">white/16 · hover</div></div>
13
+ <div class="sw"><div class="chip" style="background:var(--card);border:1px solid var(--border-control)"></div><div class="n">--border-control</div><div class="v">white/15 · a field</div></div>
14
+ <div class="sw"><div class="chip" style="background:var(--card);border:1px solid var(--border-focus)"></div><div class="n">--border-focus</div><div class="v">white/22 · focused</div></div>
15
+ <div class="sw"><div class="chip" style="background:var(--card);border:1px solid var(--border-selected)"></div><div class="n">--border-selected</div><div class="v">white/30 · chosen</div></div>
16
+ <div class="sw"><div class="chip" style="background:var(--card);border:1px solid var(--ring);box-shadow:var(--ring-focus)"></div><div class="n">--ring</div><div class="v">white/40 · 3:1, gated</div></div>
17
+ </div></body></html>
@@ -10,5 +10,5 @@
10
10
  <div style="display:flex;flex-direction:column;gap:14px">
11
11
  <div class="row"><span style="font-size:10px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--text-helper)">Enso → hanzo.app → Hanzo Cloud</span><span class="meta">10px · 600 · tracking-widest</span></div>
12
12
  <div class="row"><span style="font-size:12px;font-weight:500;letter-spacing:.06em;text-transform:uppercase;color:var(--neutral-500)">Workspace</span><span class="meta">sidebar section · 12px · 500</span></div>
13
- <div class="row"><span style="display:inline-flex;align-items:center;gap:8px;padding:8px 16px;border-radius:99px;border:1px solid var(--border-hairline);background:var(--white-05);font-size:14px;color:var(--neutral-200)">Introducing Enso · Hanzo Cloud</span><span class="meta">EyebrowBadge</span></div>
13
+ <div class="row"><span style="display:inline-flex;align-items:center;gap:8px;padding:8px 16px;border-radius:99px;border:1px solid var(--border);background:var(--white-05);font-size:14px;color:var(--neutral-200)">Introducing Enso · Hanzo Cloud</span><span class="meta">EyebrowBadge</span></div>
14
14
  </div></body></html>
@@ -8,7 +8,7 @@
8
8
  .meta{font-size:10px;color:var(--neutral-600);font-family:var(--font-mono);white-space:nowrap}
9
9
  </style></head><body>
10
10
  <div style="display:flex;flex-direction:column;gap:10px">
11
- <pre style="margin:0;padding:14px;background:var(--card);border:1px solid var(--border-hairline);border-radius:var(--radius-lg);font-size:12px;line-height:1.7;color:var(--neutral-300)">$ curl https://api.hanzo.ai/v1/chat/completions \
11
+ <pre style="margin:0;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:var(--radius-lg);font-size:12px;line-height:1.7;color:var(--neutral-300)">$ curl https://api.hanzo.ai/v1/chat/completions \
12
12
  -H "Authorization: Bearer $HANZO_API_KEY"</pre>
13
13
  <div class="row" style="gap:18px"><span class="mono" style="font-size:13px;color:var(--neutral-200)">enso-pro</span><span class="mono" style="font-size:13px;color:var(--neutral-400)">1,284,902 tokens</span><span class="mono" style="font-size:13px;color:var(--neutral-500)">--surface-card</span></div>
14
14
  </div></body></html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/design",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "packageManager": "pnpm@11.17.0",
5
5
  "description": "Hanzo Design System \u2014 monochrome, dark-default tokens + components + brand assets, the single source of truth for every Hanzo surface. CSS + typed programmatic tokens.",
6
6
  "license": "BSD-3-Clause",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "scripts": {
34
34
  "gen": "node scripts/gen-tokens.mjs",
35
- "test": "node scripts/check-tokens.mjs && node scripts/lint.mjs components",
35
+ "test": "node scripts/check-tokens.mjs && node scripts/lint.mjs components guidelines",
36
36
  "build": "pnpm gen && pnpm test && tsc -p tsconfig.json",
37
37
  "prepublishOnly": "pnpm build",
38
38
  "lint": "node scripts/lint.mjs"
package/scripts/lint.mjs CHANGED
@@ -29,7 +29,18 @@ const TOKENS = new Set()
29
29
  const EXT = new Set(['.css', '.scss', '.jsx', '.tsx', '.js', '.ts', '.vue', '.svelte', '.html'])
30
30
  const SKIP = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'out', 'coverage', 'vendor', '__pycache__'])
31
31
  // Third-party marks keep their own hex by design (DESIGN.md §2.4); so do the
32
- // token files themselves, which are where raw values are SUPPOSED to live.
32
+ // token files themselves, which are where raw values are SUPPOSED to live, and
33
+ // the specimen cards, whose whole job is to render a palette swatch at its
34
+ // literal value.
35
+ //
36
+ // This exempts those paths from the VALUE rules only. It used to skip them
37
+ // entirely, and rule 1 — "a var() must resolve" — is not a value rule, it is a
38
+ // correctness rule, and the exemption hid seven live instances of the exact
39
+ // defect this package documents: `guidelines/*.card.html` drew borders from
40
+ // `--border-hairline` and `--border-card`, neither of which anything declares.
41
+ // An undefined custom property makes the declaration invalid, `border-color`
42
+ // falls back to `currentColor`, and the specimen cards for this system's own
43
+ // border scale had been painting near-white hairlines on black.
33
44
  const EXEMPT = /(^|\/)(tokens|assets|logos|providers|ui_kits|guidelines)(\/|$)|\.card\.html$/
34
45
 
35
46
  const walk = (p, out = []) => {
@@ -65,15 +76,11 @@ const flag = (file, line, rule, detail, fix) =>
65
76
  findings.push({ file, line, rule, detail, fix })
66
77
 
67
78
  // ── the rules ────────────────────────────────────────────────────────────
68
- function lintFile(abs, root) {
69
- const rel = relative(root, abs).split(sep).join('/')
70
- if (EXEMPT.test('/' + rel)) return
71
- const raw = readFileSync(abs, 'utf8')
72
- const src = strip(raw)
73
- const isStyle = /\.(css|scss)$/.test(rel)
74
-
75
- // 1. var() must resolve — against the design tokens or a local declaration.
76
- // This is the menu that painted with undefined tokens.
79
+ // 1. var() must resolve — against the design tokens or a local declaration.
80
+ // This is the menu that painted with undefined tokens. It runs on EVERY
81
+ // file, including the ones exempt from the value rules: a swatch is allowed
82
+ // to state a hex, and is not allowed to name a token that does not exist.
83
+ function lintUnresolved(rel, src) {
77
84
  const local = new Set([...src.matchAll(/--([A-Za-z0-9-]+)\s*:/g)].map((m) => m[1]))
78
85
  for (const m of src.matchAll(/var\(\s*--([A-Za-z0-9-]+)\s*(\)|,)/g)) {
79
86
  const [, name, close] = m
@@ -83,6 +90,15 @@ function lintFile(abs, root) {
83
90
  `var(--${name}) — nothing declares it`,
84
91
  'use a token from @hanzo/design or declare it locally')
85
92
  }
93
+ }
94
+
95
+ function lintFile(abs, root) {
96
+ const rel = relative(root, abs).split(sep).join('/')
97
+ const raw = readFileSync(abs, 'utf8')
98
+ const src = strip(raw)
99
+ lintUnresolved(rel, src)
100
+ if (EXEMPT.test('/' + rel)) return
101
+ const isStyle = /\.(css|scss)$/.test(rel)
86
102
 
87
103
  // 2. no raw colour in a surface. The theme cannot reach a literal.
88
104
  for (const m of src.matchAll(/#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})\b|\b(?:rgba?|hsla?)\(/g)) {
package/styles.css CHANGED
@@ -818,7 +818,9 @@
818
818
  UA's border, which puts two typefaces and a foreign blue focus ring inside
819
819
  Hanzo cards on every surface that has not styled its own fields yet. The
820
820
  rules below are what a control looks like here. --border-control, NOT
821
- --border: the boundary IS the affordance, so it is the rung that owes 3:1. */
821
+ --border: a field's edge is its own duty and its own rung, so a surface can
822
+ retune fields without touching every divider on the page. It owes no
823
+ contrast ratio — the whole budget goes to --ring, below. */
822
824
  :where(input,select,textarea,button){font:inherit;color:inherit}
823
825
  :where(input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]),select,textarea){
824
826
  background:var(--surface-2);
@@ -896,7 +898,7 @@
896
898
  every scrolling surface in the product. 6px, no track, thumb on the same
897
899
  hairline ladder as everything else. Both syntaxes ship because they are
898
900
  disjoint — `scrollbar-*` is Firefox and the `::-webkit-*` pseudos are
899
- Chromium/Safari; neither engine reads the other. */
901
+ Chromium/Safari; neither engine reads the other.
900
902
  The thumb is a --white-* rung, so it does not invert; the `.light`
901
903
  restatements sit here rather than in colors.css because a scrollbar is an
902
904
  element default and this file is where element defaults live. Everything
package/tailwind.css CHANGED
@@ -841,7 +841,9 @@
841
841
  UA's border, which puts two typefaces and a foreign blue focus ring inside
842
842
  Hanzo cards on every surface that has not styled its own fields yet. The
843
843
  rules below are what a control looks like here. --border-control, NOT
844
- --border: the boundary IS the affordance, so it is the rung that owes 3:1. */
844
+ --border: a field's edge is its own duty and its own rung, so a surface can
845
+ retune fields without touching every divider on the page. It owes no
846
+ contrast ratio — the whole budget goes to --ring, below. */
845
847
  :where(input,select,textarea,button){font:inherit;color:inherit}
846
848
  :where(input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]),select,textarea){
847
849
  background:var(--surface-2);
@@ -919,7 +921,7 @@
919
921
  every scrolling surface in the product. 6px, no track, thumb on the same
920
922
  hairline ladder as everything else. Both syntaxes ship because they are
921
923
  disjoint — `scrollbar-*` is Firefox and the `::-webkit-*` pseudos are
922
- Chromium/Safari; neither engine reads the other. */
924
+ Chromium/Safari; neither engine reads the other.
923
925
  The thumb is a --white-* rung, so it does not invert; the `.light`
924
926
  restatements sit here rather than in colors.css because a scrollbar is an
925
927
  element default and this file is where element defaults live. Everything
package/tokens/base.css CHANGED
@@ -83,7 +83,9 @@
83
83
  UA's border, which puts two typefaces and a foreign blue focus ring inside
84
84
  Hanzo cards on every surface that has not styled its own fields yet. The
85
85
  rules below are what a control looks like here. --border-control, NOT
86
- --border: the boundary IS the affordance, so it is the rung that owes 3:1. */
86
+ --border: a field's edge is its own duty and its own rung, so a surface can
87
+ retune fields without touching every divider on the page. It owes no
88
+ contrast ratio — the whole budget goes to --ring, below. */
87
89
  :where(input,select,textarea,button){font:inherit;color:inherit}
88
90
  :where(input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]),select,textarea){
89
91
  background:var(--surface-2);
@@ -161,7 +163,7 @@
161
163
  every scrolling surface in the product. 6px, no track, thumb on the same
162
164
  hairline ladder as everything else. Both syntaxes ship because they are
163
165
  disjoint — `scrollbar-*` is Firefox and the `::-webkit-*` pseudos are
164
- Chromium/Safari; neither engine reads the other. */
166
+ Chromium/Safari; neither engine reads the other.
165
167
  The thumb is a --white-* rung, so it does not invert; the `.light`
166
168
  restatements sit here rather than in colors.css because a scrollbar is an
167
169
  element default and this file is where element defaults live. Everything